Reputation: 191
Let's assume i want to create a sports event Event-Sourcing Project with CQRS.
How would i create the projection for that?
Game with Winner
GameID | Location | TeamNameOne | TeamNameTwo | Winner | PointsTeamOne | PointsTeamTwo |
---|---|---|---|---|---|---|
1234 | Munich | Avengers | Suicide Squad | Avengers | 48 | 30 |
But how would i design the Team has many players projection? With a JSON Field?
TeamID | TeamName | Players |
---|---|---|
432 | Avengers | [{"name": "Man, Iron", "number": 34}, {"name": "America, Captain": "number": 1}...] |
Or with a line for each player?
TeamId | TeamName | PlayerId | PlayerName |
---|---|---|---|
432 | Avengers | 34 | Stark, Tony |
432 | Avengers | 1 | America, Captain |
The same with Events for each Game, that could be much, depending on how granular i want to track each activity.
I thought about a DocumentBased Database for the Events in a Game, so each Game could include all the activities in one Field (Like in the Players-Column for the Teams). But then it would get complex too, because Game contains Acitvity contains Acitvity's Player
Is a GraphDB like Neo4J better for that? I think, but then i have to start creating "queries" and the projectors are not independent anymore.
And then the question for the Aggregate design. Because i am not sure if i should add a List of Player IDs in a TeamAggregate and a List of Events for a Game.
Upvotes: 0
Views: 219
Reputation: 487
I've been thinking about this issue a lot myself, and it seems to me that the more 'read-optimised' you want, the more data you have to store (and the more complex the writing becomes).
Your point about each activity containing a copy of the user record is a great example.
You could imagine on the front-end, that there is a tool-tip for each activity that happens, which when the user hovers over the tool-tip displays a link to that particular player and their profile picture.
Having that read-model 'ready-to-view' would mean potentially copying user data many times into each event.
Then if a user changes details (like a new profile picture), then you have to iterate over large data structures and update the new value across the board. This adds a lot of complexity to making updates to this projection.
In terms of how to store this data, I'd probably go with a key-value document. I find those well suited to displaying on a front-end because they form a hierarchal tree, which is the same as HMTL, so there is a natural mapping between the two.
Like many things in software, there are trade-offs. The less joining and more 'ready-to-view' you want the data, the more data duplication and more complexity of keeping consistency.
You can make the joins cheaper by using key-value stores (as they have near constant lookup time).
So you could have this type of structure:
{
gameId:'sdk',
gameEvents: [
{
playerId: 'abc',
eventType: 'FOUL',
}
// etc.
],
players: {
abc: {
name: 'billy',
profilePicture: 'billy.png',
},
// etc.
}
}
Then all your front-end has to do, is each component where the tool-tip is rendered, you can do like:
<div>
<tooltip>
<content> {{ event.eventType }} </content>
<hover> {{ data.players[event.playerId].name }} </content>
</tooltip>
</div>
Upvotes: 1