I’m working with Alessandro (from Codice/Plastico) at a really interesting customer (not only for the frequent fashion shows ;-) ) on a really interesting project where we are applying lots of Domain Driven Design concepts, using Event Sourcing and CQRS strategies where everything is persisted on MongoDB.

Being used to all the built-in features provided out-of-the-box by RavenDB the initial daily usage of MongoDB has been quite full of friction (at least for me). From a certain point of view there is a non-feature of MongoDB that after all is a big win when used in a domain driven design based project: “the missing linq provider”, and I have to admit that “I’m lovin’ it” <cit.>.

The C# driver we are using (v1.3) has no built in support for linq queries, the v1.4 introduce the linq support, this basically means that every query you issue to the database looks like the following statement:

Query.EQ( "Author", authorId )

Or a sort by clause looks like:

SortBy.Descending( "PostedAt" )

As you can see it simply means that you have to revert back to “strings” backed into the code, but this let us achieve really really easily…

CQRS

Take a look at the following aggregate that represents a message on a board (something really similar to a Facebook wall):

public class Message : AggregateRoot
{
	[BsonElement( "Board" )]
	private OwnerBoard board;
 
	[BsonElement( "Sender" )]
	private Sender sender;
 
	[BsonElement( "Text" )]
	private string text;
 
	[BsonElement( "PostedAt" )]
	[BsonRepresentation( BsonType.Document )]
	private DateTimeOffset postedAt;
 
	[BsonElement( "Attachments" )]
	private IEnumerable<Attachment> attachments;
 
	readonly IMessageBroker broker;
	readonly IOperationContext context;
	readonly IMongoRepository mongo;
 
	private Message( IMessageBroker broker, IMongoRepository mongo, IOperationContext context )
	{
		this.broker = broker;
		this.context = context;
		this.mongo = mongo;
	}
 
	internal void InitializeMandatoryParameters( OwnerBoard board, Sender sender, string text, IEnumerable<Attachment> attachments )
	{
		this.postedAt = DateTimeOffset.Now;
		this.board = board;
		this.sender = sender;
		this.text = text;
		this.attachments = attachments;
 
		this.Save( new MessageCreated( this.context.GetCurrentUserView(), this.Id ) );
	}
 
	void Save( DomainEvent @event )
	{
		this.mongo.Save( this, true );
		if( @event != null ) this.broker.Broadcast( @event.AsMessageFrom( this ) );
	}
}

There is one really really important thing to notice: no public properties, well no properties at all, only behaviors (I’ve dropped the majority of the code).

What happens is that there is a factory (a MessageFactory), tightly coupled with the message class that is responsible for the creation of a new message (and is the only one that has access to the InitializeMandatoryParameters internal method, since we are in an event source based scenario with no transaction support every single time the state of an aggregate changes the aggregate must be consistent and will self save it's own state, notifying (using a domain event) the outside world that something has happened (in the past and asynchronously).

Now, given the serialization/deserialization nature of a document database (not only MongoDB in this case) we can now issue a query like the following:

var messages = mongo.Find<MessageView>
(
	query: Query.EQ( "Sender.Id", sender ),
	sortBy: SortBy.Descending( "PostedAt.DateTime" )
);

What we achieved is that we now have a projection of the Message aggregate, a read-only projection, just for the query part of the CQRS process, auto-magically handled by the database serialization provider giving only a bunch of conventions:

[BsonIgnoreExtraElements]
public class MessageView
{
	public String Id { get; private set; }
 	public OwnerBoard Board { get; private set; }
 	public Sender Sender { get; private set; }
 	public string Text { get; private set; }
 	public IEnumerable<Attachment> Attachments { get; private set; }
}

This class is automatically mapped to the correct MongoDB structures because the naming of the properties matches the BsonElement(s) on the aggregate. The cool thing is that when you have the data in the shape you need you do not need to issue complex queries :-)

Poor man Map/Reduce

The above sample is basically a projection, we simply need a subset of the data held by the aggregate and the sample above is the easiest way to go with MongoDB; but what happens if you need to aggregate data to produce a different shape that merge data into a new (read-only) structure, a sort of materialized view, or in no-sql language, a Map/Reduce?

Given the fact that we are using an event sourcing based approach is really easy to have a domain event handler whose role is to transform the data, each time they change, in the required shape.

Easy peasy :-) without the need to deal with the JavaScript implementation of the MongoDB Map/Reduce.

.m