Note that there are some explanatory texts on larger screens.

plurals
  1. POStoring and updating read model in a CQRS + ES system
    primarykey
    data
    text
    <p><strong>Background</strong></p> <p>I have a system that is using CQRS + ES and in this system there are aggregates such as blog posts or issues that are persisted in the event store and send events over to the query side to persist the read model via projections.</p> <p><em><strong>In the case of a an issue or post being created it is a fairly straight forward</em></strong></p> <ul> <li>Client creates a command to create a new issue</li> <li>A command handler creates a new issue aggregate and saves the changes in the event store</li> <li>When the aggregate applies the change it fires off an IssueCreatedEvent or similar</li> <li>A projection on the read side will listen for this and create an issue model and any other denormalised data that it wants (such as a cutdown IssueListItem for querying a list of all issues)</li> </ul> <p>If a change is made to the issue and an appropriate event is raised on the write side such as <em>IssueStatusChanged</em> and handled on the read side accordingly. Load up the two de-normalised models on the read side update the status from the event and save. Easy.</p> <p><em><strong>How do you handle relations such as comments?</em></strong></p> <p>I am implementing a comment system where users can post comments on an issue or a blog post. My first thought was to have these comments added to the issue or post aggregate on the write side for consistency. When I thought about this though I realised that this would likely introduce a lot of unnecessary concurrency issues like when somebody is updating an issue and someone else has come and posted a new comment.</p> <p>This led me to think that I should model comments themselves as their own aggregate root. This way comments posted to a blog post or issue will not cause conflicts with the issue itself.</p> <p>So assuming I model comments on the write side as aggregates in this way, I have two questions;</p> <p><strong>1) Does the issue or post aggregate on the write side still need to store this relationship?</strong> The comment aggregate itself already stores which item it was posted too with an id reference.</p> <p>If so, I was thinking of having the issue aggregate subscribe to the comment created event and add its own reference.</p> <pre><code>public class Issue : AggregateRoot, IEventHandler&lt;CommentCreatedEvent&gt; { private ICollection&lt;Guid&gt; _Comments; public void Handle(CommentCreatedEvent @event) { _Comments.Add(@event.AggregateId) } } </code></pre> <p>Is this sufficient or not needed since the comment already stores a reference to its parent? This data isn't really needed on the write side and is more important on the read side when it is the parent that is loaded up with all comments.</p> <p><strong>2) On the read side what is the best way to store this data?</strong></p> <p>Specifically, in order to make this data easy to update I would need to put in another table for comments and join them to the appropriate post or issue. After I have finished with <em>comments</em> I will be implementing a <em>following</em> system where users can follow an item to receive updates. Going down this path however will very quickly lead me back to a highly normalised schema on the read side which defeats the purpose of an optimised, denormalised read model.</p> <p>I was therefor thinking of adding a single column to the issue table for example that stored all comments as a serialised json clob or something. That way when changes come in to comments I can still pull out one record to load up the issue, make the appropriate changes to the comments (such as updating an existing comment, adding a new comment or removing one) and re-saving the record. From a read perspective, the entire issue can still be retrieved in one go.</p> <p>The problem I see with this approach is that if a user changes their profile picture or profile name for example, I would have to load up every single issue and/or post, load up the comments and make the appropriate changes in the comment info.</p> <p>I also wonder how document databases (something else I have been considering for the read side) get around this issue of updating nested data?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload