Skip to content
jlarsson edited this page Sep 11, 2011 · 10 revisions

A KiwiDB database is called a collection and each collection has a single database file on disk.

var collection = new Collection(@"c:\temp\data.kiwidb");

Instatiating a collection really does nothing in itself, and the file name and extension is totally of your choice. If the physical file doesn't exist, it will be created by the first operation touching it.

Now lets put stuff in the collection. And by stuff we mean plain old .NET objects, also called documents in the Nosql world. The documents you can put in a collection can have any combination of lists, classes, dictionaries and simple values. The only requirement is that the stuff you put in must be serializable to and deserializable from Json.

Also, each document is associated via a key. This is not negotiable.

Currently

  • keys are always strings (I would love to loosen this up...)
  • keys are case sensitive (...and this could also be more, hrm, flexible)
  • keys are not part of the data, and this is an important difference compared to, say, MongoDB
  • keys are always created by the application, never by KiwiDB

Get

If you know the key of a stored document, access is easy.

For untyped access, the result is an IJsonValue or null.

IJsonValue user = collection.Get("key1");

Typed access map back to the same type.

User user = collection.Get<User>("key1");

Update

An update is always an UPSERT, that is if the key is unique, the document is added, otherwise it is overwritten.

The result of an update is the previously stored value or null.

For untyped updates, the result is an IJsonValue, i.e. the internal Json representation of the previsously stored value.

IJsonValue previous = collection.Update("key1",new {Name = "John"});

Typed access map back to the same type.

User previous = collection.Update<User>("key1",new User(){Name = "John"});

Remove

The remove operation accepts a single argument, and returns the deleted value or null.

For untyped deletes, the result is an IJsonValue, i.e. the internal Json representation of the previsously stored value.

IJsonValue deleted = collection.Remove("key1");

Typed access map back to the same type.

User deleted = collection.Remove<User>("key1");

Batch operations

Transactions or series of operations can be combined. The advantages of this is typically

  • huge performance gain compared to doing a sequence of isolated operations
  • ability to keep consistency over a sequence of operations.
  • Modifying batches via ExecuteWrite
  • Readonly batches via ExecuteRead
// Filter for finding all objects with value _"obsolete"_ in either string property or as member in list.
var objectsToDeleteFilter = new {Tags = "obsolete"};
// Execute write allows us to provide a delegate wich is executed in a logical session.
List<string> deletedKeys = collection.ExecuteWrite(c => {
	// Find all keys of unwanted objects
	var keys = (from record in c.Find(objectsToDeleteFilter)
				select record.Key)
				.ToList();
	// Remove them one by one
	foreach(var key in keys)
	{
		c.Remove(key);
	}
	return keys;
});

The unbatched equivalent is typically atleast N times slower (and N varies alot of course...).

// Filter for finding all objects with value _"obsolete"_ in either string property or as member in list.
var objectsToDeleteFilter = new {Tags = "obsolete"};

var keys = (from record in c.Find(objectsToDeleteFilter)
			select record.Key)
			.ToList();
// Remove them one by one
foreach(var key in keys)
{
	collection.Remove(key);
}

Connection pooling, i.e. Collection caching

No need really, since collections have very little state except a path. But there's no harm in caching or pooling and it will not impose any threading issues or other evils.

Clone this wiki locally