Getting Started With LiteDB

Introduction

I will be demonstrating with a sample application on how one can simply make use of LiteDB for managing the documents. In our case, we will be managing a collection of ‘Issue’ documents.

Before diving into the real implementation, let us try to have some basic understanding of LiteDB.

LiteDB is a document store based NoSQL database developed by “Mauricio David”. Depending upon the use case, one can use LiteDB as a light weight database. It is completely open source and free to use even for commercial use.

The sample application that we are dealing with focuses mostly on performing CRUD operation on a single entity named ‘Issue’. To be specific, the demo app makes use of LiteDB and performs CRUD operation for managing the issues. Also in addition to that, the demo app has a basic search functionality, which will filter the issues by specific criteria; that is by ‘Issue type’ and ‘Date’ and updates GridView with the source set to the filtered issues.

Background

Please read through the following mentioned article to understand the basics about LiteDB Document Store.

Coding the Sample Application

Here’s the snapshot of our demo application for managing issues. As you can see, it’s a single screen with two textboxes and few buttons and a Gridview which is used to display all the stored issues.

Manage Issue

The following is the code snippet of our Issue entity. You can notice below, every single document that we are dealing with requires a Bson Id (which is a GUID). Below you can see the Issue Id is being attributed with a custom attribute “BsonID” indicates the property ‘IssueId’ to be used as a Bson Id.
  1. public class Issue  
  2. {  
  3.     [BsonId]  
  4.     public Guid IssueId  
  5.     {  
  6.         get;  
  7.         set;  
  8.     }  
  9.     public DateTime DateTime  
  10.     {  
  11.         get;  
  12.         set;  
  13.     }  
  14.     public string ErrorText  
  15.     {  
  16.         get;  
  17.         set;  
  18.     }  
  19.     public string IssueType  
  20.     {  
  21.         get;  
  22.         set;  
  23.     }  
  24. }  
The demo app contains a single main screen for managing all the issues. Every single issue that gets stored in LiteDB has an error text and is associated with an issue type (warning, error, info etc), date and time.

We will be making use of a repository pattern, which encapsulates the CRUD operation logic for managing the issues.

The following is the code snippet for creating a new issue:
  1. Firstly, we have to open a data file by creating an instance of LiteEngine with the specific path where the LiteDB is stored. If the file exists, it will open else it will create a new one.

  2. Next, using LiteEngine instance and get a typed collection of issues.

  3. Make a call to “Insert” method with the issue entity to create a new document in LiteDB.

  4. Make a call to a method ‘IndexIssue’ which is a private method, will take care of indexing the fields within the issue entity.
    1. public void Add(Issue issue)  
    2. {  
    3.     // Open data file (or create if not exits)  
    4.     using(var db = new LiteEngine(liteDBPath))  
    5.     {  
    6.         var issueCollection = db.GetCollection < Issue > ("issues");  
    7.         // Insert a new issue document  
    8.         issueCollection.Insert(issue);  
    9.         IndexIssue(issueCollection);  
    10.     }  
    11. }  

Below you can see the code snippet for indexing the issue entity properties. By making a call to ‘EnsureIndex’ with the lambda expression for the property that we are interested in indexing will make the fields to be indexed in LiteDB. Ones the document is indexed with the necessary fields, we can easily filter issues by specific criteria.

  1. private void IndexIssue(Collection < Issue > issueCollection)  
  2. {  
  3.     // Index on IssueId  
  4.     issueCollection.EnsureIndex(x => x.IssueId);  
  5.     // Index on ErrorText  
  6.     issueCollection.EnsureIndex(x => x.ErrorText);  
  7.     // Index on DateTime  
  8.     issueCollection.EnsureIndex(x => x.DateTime);  
  9.     // Index on IssueType  
  10.     issueCollection.EnsureIndex(x => x.IssueType);  
  11. }  
Let us now take a look into the update operation. The following code snippet updates an existing issue by making a call to “Update” method of Collection type instance. All you have to make sure is, the issue instance has the Issue Id set with the GUID to update an existing issue document.

We will shortly see how the issue instance is constructed and the GUID is set to update an existing issue.
  1. public void Update(Issue issue)  
  2. {  
  3.     // Open data file (or create if not exits)  
  4.     using(var db = new LiteEngine(liteDBPath))  
  5.     {  
  6.         var issueCollection = db.GetCollection < Issue > ("issues");  
  7.         // Update an existing issue document  
  8.         issueCollection.Update(issue);  
  9.     }  
  10. }  
The following is the code snippet to delete the issue document. All you have to do is, pass in the Issue id (The GUID of an existing issue in LiteDB). We have to get the Collection instance for the ‘Issue’ type, then make a call to its ‘Delete’ method with a lambda expression matching the Issue Id.
  1. public void Delete(Guid issueId)  
  2. {  
  3.     using(var db = new LiteEngine(liteDBPath))  
  4.     {  
  5.         var issues = db.GetCollection < Issue > ("issues");  
  6.         issues.Delete(i => i.IssueId == issueId);  
  7.     }  
  8. }  
Now let us take a look into how we can fetch all issues (a collection of Issue documents). The following is the code snippet for the same.
  1. Create an instance of LiteEngine with the path where the LiteDB file is stored.

  2. Get a ‘Collection’ type instance for the ‘Issue’ type.

  3. Make a call to ‘All’ method to return all the issue documents stored in LiteDB. The results type will be Collection<Issue>, but the function return type is of IList type. Hence, an additional code required to build the issues to return.
    1. public IList < Issue > GetAll()  
    2. {  
    3.     var issuesToReturn = new List < Issue > ();  
    4.     using(var db = new LiteEngine(liteDBPath))  
    5.     {  
    6.         var issues = db.GetCollection < Issue > ("issues");  
    7.         var results = issues.All();  
    8.         foreach(Issue issueItem in results)  
    9.         {  
    10.             issuesToReturn.Add(issueItem);  
    11.         }  
    12.         return issuesToReturn;  
    13.     }  
    14. }  

The following is the code snippet which returns a collection of ‘Issue’ instances for the matched issue type and date. Notice below, though we pass a DateTime instance we will be only making use of a ‘Date’ value.

There is a slight performance issue with the following code as we can’t really filter the issue by Date. There is a reason for that; when we are creating an issue document, we are indexing the issue ‘DateTime’ property. That said, you can still be able to filter by ‘DateTime’ as it is indexed but not partially by its date component.

  1. public IList < Issue > Get(string issueType, DateTime datetime)  
  2. {  
  3.     var issuesToReturn = new List < Issue > ();  
  4.     using(var db = new LiteEngine(liteDBPath))  
  5.     {  
  6.         var issues = db.GetCollection < Issue > ("issues");  
  7.         IEnumerable < Issue > filteredIssues;  
  8.         if (issueType.Equals("All")) filteredIssues = issues.All();  
  9.         else filteredIssues = issues.Find(i => i.IssueType.Equals(issueType));  
  10.         foreach(Issue issueItem in filteredIssues)  
  11.         {  
  12.             issuesToReturn.Add(issueItem);  
  13.         }  
  14.         return issuesToReturn.FindAll(i => i.DateTime.Date == datetime.Date);  
  15.     }  
  16. }  
Points of Interest

There is always something new that I am learning. Especially while researching on NoSQL databases, I was looking for a simple and easy to use database. From what I experienced, LiteDB is one of the most simplest one that I came across. What I strongly believe is, this is what a beginner would expect to learn and understand about NoSQL.

Don’t forget to read about the limitations and use cases. Apart from that, one should be good to go in using LiteDB with zero installation or nothing much required in setting up and getting started in coding.
I am extremely happy in building the demo app. Also I am thankful to the creator of LiteDB for building the light weight NoSQL database. Well I have to say one last thing about this article. This article is inspired from Mauricio David’s article in introducing LiteDB to the community.

I hope this article gave a basic high level understanding on how to use LiteDB. There are many other aspects like the support for Transactions, etc. which we will see in coming articles.