Programming Seeking Understanding
The blog of Mark Cheeseman

Aggregates and Documents

The most effective principle we have found in determining what should be contained in a RavenDB document is to follow the principles around DDD aggregates. An aggregate is a collection of objects, with one of the those objects as the root, which represents the smallest collection of objects that must be kept consistent at a time. Typically, an aggregate corresponds to the extent of data modified in a single transaction.

Take the following example:

class Invoice
{
	public string Id {get; set;}
	public List<InvoiceLine> Lines {get; set}
	public decimal Total {get; set;}
}
class InvoiceLine
{
	public string ItemDescription {get; set;}
	public decimal Amount {get; set;}
}

It is likely that Invoice.Total should always be consistent with Invoice.Lines.Sum(l => l.Amount). This should not be eventually consistent, it should be immediately consistent. Other parts of the system may be making business decisions based on Invoice.Total, and it will not do for them to be making decisions based on an incorrect total.

Consequently, Invoice will be an aggregate, and a single invoice will end up in a single document.

Invoice i = new Invoice()
{
	...
	Lines = ...
}
ravenSession.Store(i);

Things get more interesting if we consider what happens if we consider that the Invoice belongs to a customer. There are at least three possibilities for how the invoice is related to the customer.

Use a Customer key

class Invoice
{
	public string Id {get; set;}
	public string CustomerId {get; set;}
	public List<InvoiceLine> Lines {get; set}
	public decimal Total {get; set;}
}

In this case, CustomerId is the document key for whatever the Customer entity is. This obviously corresponds quite closely to how the situation may be envisage if using a relational database.

Use a Customer Value object

class CustomerValueObject
{
	public string Id {get; set;}
	public string Name {get; set;}
}
class Invoice
{
	public string Id {get; set;}
	public CustomerValueObject Customer {get; set;}
	public List<InvoiceLine> Lines {get; set}
	public decimal Total {get; set;}
}

In this case, the CustomerValueObject is a snapshot of the Id and Name of the Customer at the time the Invoice is created. If the customer’s name changes, it would need to be determined whether it is necessary to update any of the corresponding denormalized CustomerValueObject.Name properties. While I have suggested that the focus of a document should be on issues of mutation and consistency, one advantage of this design is that if you have a collection of Invoices and want to use them for a view model, it is not necessary to hit the database to get the customer’s name (assuming for the sake of the example you want to show a list of invoices and the name of each invoice’s customer).

Note that exactly what CustomerValueObject is, is not the important point here. The main point is that it is not an instance of Customer, but rather in most cases a subset of the Customer object. On our project, we have settled for using something like this for virtually all references:

class EntityReference
{
	public string Id {get; set;}
	public string Name {get; set;}
}

.

Make Customer the aggregate, including the invoices

class Customer
{
	public string Id {get; set;}
	public string Name {get; set;}
	public List<Invoice> Invoices {get; set;}
}

This is the sort of design that I would suggest may be problematic. It’s main apparent advantage is that it is possible to hit the database once, get a single document, and display every invoice that a customer has ever had. Furthermore, if the customer’s name changes, it avoids the (potential) problem of solution #2, that a denormalized customer name becomes inconsistent. The disadvantages are:

An easy question to ask one-self is this: am I deciding on the document (aggregate) boundaries on the basis of consistency requirements, or on the basis of a view of the data (for example, a view model required for a page). If the former, you are likely on the right path. On the other hand, if the extent of the document is determined by the fact that there exists some page in your application that shows some amount of data and it is possible to put all that data into a document, and hence, achieve 1 page = 1 db hit, then you may want to carefully consider the disadvantages.

A Note on Aggregates and Domain Driven Design

Aggregate is a technical term in Domain Driven Design (DDD). The definitive explanation is found in Eric Evans, Domain-Driven Design . An excellent worked example is found in Vaughn Vernon, Implementing Domain-Driven Design, (chapter 10 on Aggregates is one of the best in the book). For a taste of Vernon’s book see his articles, Effective Aggregate Design, which were subsequently revised and turned into the Aggregates chapter in his book.