Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CQRS (event sourcing): Projections with multiple aggregates

I have a question regarding projections involving multiple aggregates on a CQRS architecture.

For example sake, suppose I have two aggregates WorkItem and Developer and that the following events happen sequentially (but not immediately)

  1. WorkItemCreated (workItemId)
  2. WorkItemTitleChanged (workItemId, title)
  3. DeveloperCreated (developerId)
  4. DeveloperNameChanged (developerId, name)
  5. WorkItemAssigned (workitemId, DeveloperId)

I wish to create a projection which is as "inner join" of developer-workitem:

| WorkItemId | DeveloperId | Title  | DeveloperName | ... |
|------------|-------------|--------|---------------|-----|
| 1          | 1           | FixBug | John Doe      | ... |

The way I am doing my projections is incrementally. Meaning I load the saved projections from the database and apply the remaining events as they come.

My problem is, the event responsible for creating a row on the projection table is WorkItemAssigned. However, that event does not carry required information from previous events (workitem title, developer name, etc.)

In order to have the required information by the time WorkItemAssigned, I have to load all events from the eventstore, keep states in-memory for all WorkItems and Developers so I have the required information by the time a WorkItemAssigned event arrives.

Sure, I could have a projection for Workitem, another for Developer and query them to retrieve their last states. But it seems like a lot of work, if I am to create projections for each aggregate separately, I might as well create a database view to inner-join them (In fact, that is what I am doing.)

I am not doing all this by hand, I am currently using a good framework called EventFlow, but it doesn´t direct me to answer this question.

This is a question on fundamentals of CQRS, and I fell I am missing something here.

like image 625
Fabio Marreco Avatar asked Dec 09 '18 00:12

Fabio Marreco


People also ask

What are aggregates in CQRS?

In terms of Domain-Driven Design Aggregate is a logical group of Entities and Value Objects that are treated as a single unit (OOP, Composition). Aggregate Root is a single one Entity that all others are bound to.

What is CQRS projection?

Projection is about deriving current state from the stream of events. For instance, consider a situation, where a stream of events is published out by a server to all subscribers.

What are aggregates in Event Sourcing?

An aggregate is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each aggregate has a root and a boundary. The boundary defines what is inside the aggregate. The root is a single, specific entity contained in the aggregate.

What benefits do we get when we use Event Sourcing with CQRS?

Event sourcing is a powerful pattern and brings a lot of benefits to an application architecture if used appropriately: Makes write operations much faster as there is no read, update, and write required; write is merely appending an event to a log.


1 Answers

I don't think you are missing anything. Projecting read models in an event-sourced system presents a different set of problems than querying from a relational model. The problems are not necessarily easier or harder to solve; they are just different.

The good news is that you have a lot of choices. Event Sourcing allows you to project data in any imaginable way, so you can decide on a solution that is most suitable for each individual projection. I guess the "bad" news (I would argue it's not bad news) is that the solution to the problem is not the same every time as it is with a relational system, which is to construct a query using JOINs.

You've already identified a few possible solutions:

  • Use a relational model as one of your read models
  • When a certain type of event comes in, re-query the streams that hold the data you need and use them to project on demand

You could also simply hold some data in an interim state (in memory, a document database, the file system, etc.) that allows you to look up the data and project it when needed. So keep lists of updated WorkItems and Developers where they can be read and used whenever a WorkItemAssigned event comes in.

I would say creating a relational database as an interim or permanent read model is a perfectly viable way of solving the problem, assuming you are not trying to achieve massive scalability.

like image 128
Phil Sandler Avatar answered Sep 21 '22 12:09

Phil Sandler