I was looking for a simple file based object/document database and came across LiteDB. This gives similar functionality to MongoDB.
If you’re looking for good documentation on LiteDB, I would suggest going to Getting Started. I’ll undoubtedly duplicate some/much of what’s written there in this post which is mainly aimed at reminding me how to get up and running with LiteDB.
Getting started
It’s so easy to get started with LiteDB. Let’s first define an object model for some data that we might wish to store.
public class Artist { public string Name { get; set; } public IList<string> Members { get; set; } } public class Album { public int Id { get; set; } public Artist Artist { get; set; } public string Name { get; set; } public string Genre { get; set; } }
We need an Id property or a property marked with a BsonId attribute on our POCO object. Whilst we can get away without this for some operations, updates (for one will fail) without the Id property/BsonId.
To use LiteDB, simply install the nuget package LiteDB and now here’s the bare minimum to create/open a LiteDB database file and get a reference to the collection for our CRUD operations
using (var db = new LiteDatabase("Albums.db")) { var albums = db.GetCollection<Album>("albums"); // now we can carry out CRUD operations on the data }
Easy enough. The LiteCollection returned from GetCollection allows us to to work on our data in a very simple manner.
For example, let’s insert a new album
albums.Insert( new Album { Artist = new Artist { Name = "Led Zeppelin", Members = new List<string> { "Jimmy", "Robert", "JP", "John" } }, Name = "Physical Graffiti", Genre = "Rock" });
How about retrieving all the data, we can use
var results = albums.FindAll();
We can also query for specific data using a predicate, for example
var r = albums.Find(a => a.Artist.Name == "Alice Cooper");
Note: in this example, the Artist.Name property has not been indexed, so performance would be improved by setting an index on the data.
To update we need to get the instance from LiteDB (or at least know the Id) and then makes the changes as follows
var zep = albums.Find(a => a.Artist.Name == "Led Zeppelin").First(); zep.Artist.Members[2] = "John Paul Jones"; albums.Update(zep);
Obviously in the above we’re assuming there’s at least one item (by calling First() as obviously there might be zero, one or multiple returns), the key is how we simply call the Update method.
Deleting all items from a database can be achieved, obviously by deleting the DB file or using
albums.Delete(Query.All());
or we can delete an individual item by calling
// use the Id property albums.Delete(album.Id); // or // use a query type syntax albums.Delete(x => x.Artist.Name == "Led Zeppelin"); // or // using the Query syntax similar to deleting all items albums.Delete(Query.EQ("Artist.Name", new BsonValue("Led Zeppelin")));
Obviously the Query syntax seems a little over the top for most things, but offers more query like syntax if required.
And there’s more
Okay I’m not intending to document everything in this single post but I have to just touch on transactions. It’s great to see the ability to use ACID transactions for use with LiteDB.
So to ensure we only commit when all operations are successful we simply use
var albums = db.GetCollection<Album>("albums"); db.BeginTrans(); // multiple operations against LiteDB db.Commit();
Multiple Inserts
It seems (from the documentation etc.) that when we carry out an insert, LiteDB creates an “auto-transaction” around the insert for us (see Transactions and Concurrency. As such we should be aware that if we’re creating many inserts (for example from a list of objects) then it’s best from a performance point of view to not call insert multiple times.
Instead either using the IEnumerable overload of the Insert method or wrap all inserts within a transaction (I’m assuming this would also work – not yet tested).
This make sense, but can be easily forgotten.