cqrs and event sourcing with mongodb and php
TRANSCRIPT
![Page 1: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/1.jpg)
CQRS and Event Sourcingwith MongoDB and PHP
![Page 2: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/2.jpg)
About me
Davide Bellettini● Developer at Onebip● TDD addicted
@SbiellONE — about.bellettini.me
![Page 3: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/3.jpg)
What is this talk about
![Page 4: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/4.jpg)
A little bit of context
![Page 5: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/5.jpg)
About OnebipMobile payment platform.Start-up born in 2005, acquired by Neomobile group in 2011.
Onebip today:- 70 countries- 200+ carriers- 5 billions potential users
![Page 6: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/6.jpg)
LAMP stack
It all started with a Monolith
![Page 7: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/7.jpg)
self-contained services communicating via REST
To a distributed system
![Page 8: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/8.jpg)
First class modern NoSQL distributed dbs
Modern services
![Page 9: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/9.jpg)
But the Monolith is still there
![Page 10: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/10.jpg)
The problem
A reporting horror story
![Page 11: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/11.jpg)
We need three new reports!
― Manager
Sure, no problem!
![Page 12: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/12.jpg)
Deal with the legacy SQL schema
![Page 13: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/13.jpg)
![Page 14: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/14.jpg)
Deal with MongoDB
![Page 15: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/15.jpg)
A little bit of queries here,a little bit of map-reduce there
![Page 16: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/16.jpg)
1 month later...
![Page 17: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/17.jpg)
Reports are finally ready!
![Page 18: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/18.jpg)
until...
![Page 19: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/19.jpg)
Your queries are killing production!
― SysAdmin
![Page 20: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/20.jpg)
Still not enough!
Heavy query optimization,adding indexes
![Page 21: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/21.jpg)
Let’s reuse data from other reports(don’t do that)
![Page 22: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/22.jpg)
DB is ok, reports delivered.
![Page 23: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/23.jpg)
but then...
![Page 24: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/24.jpg)
Houston, we have a problem. Reports are not consistent (with other reports)
― Business guy
![Page 25: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/25.jpg)
![Page 26: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/26.jpg)
Mistakesweremade
![Page 27: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/27.jpg)
Lessonslearned
![Page 28: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/28.jpg)
It’s hard to compare different data in a distributed system splitted across multiple domains
#1Avoid multiple sources of truth
![Page 29: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/29.jpg)
Same words, different concepts across domains
#2Ubiquitous language
![Page 30: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/30.jpg)
Changing a report shouldn’t have side effects
#3Fault tolerance to change
![Page 31: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/31.jpg)
Most common solutions
![Page 32: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/32.jpg)
#1ETL + Map-Reduce
![Page 33: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/33.jpg)
#2
Data Warehouse + Consultants
![Page 34: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/34.jpg)
#3Mad science (Yeppa!)
![Page 35: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/35.jpg)
What we wanted
![Page 36: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/36.jpg)
No downtime in production
Consistent across domains
Must have
![Page 37: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/37.jpg)
A system elastic enough to extract any metric
Real time data
Nice to have
![Page 38: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/38.jpg)
In DDD we found the light
![Page 39: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/39.jpg)
CQRS and Event Sourcing
![Page 40: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/40.jpg)
Command-query responsibility segregation
(CQRS)
![Page 41: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/41.jpg)
![Page 42: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/42.jpg)
Commands
Anything that happens in one of your domains is triggered by a command and generates one or more events.
Order received -> payment sent -> Items queued
-> Confirmation email sent
![Page 43: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/43.jpg)
Query
Generate read models from events depending how data need to be actually used (by users and other application internals)
![Page 44: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/44.jpg)
Event SourcingThe fundamental idea of Event Sourcing is that of ensuring every change to the state of an application is captured in an event object, and that these event objects are themselves stored in the sequence they were applied.
― Martin Fowler
![Page 45: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/45.jpg)
Starting from the beginning of time, you are literally unrolling history to reach state in a
given time
Unrolling a stream of events
![Page 46: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/46.jpg)
Idea #1
Every change to the state of your application is captured in event object.
“UserLoggedIn”, “PaymentSent”, “UserLanded”
![Page 47: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/47.jpg)
Idea #2
Events are stored in the sequence they were applied inside an event store
![Page 48: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/48.jpg)
Idea #3
Everything is an event. No more state.
![Page 49: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/49.jpg)
Idea #4
One way to store data/events but potentially infinite ways to read them.
A practical exampleTech ops, business control, monitoring, accounting they all are interested in reading data from different views.
![Page 50: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/50.jpg)
Healthy NoSQL
![Page 51: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/51.jpg)
You start with this{ "_id": ObjectId("123"), "username": "Flash", "city": …, "phone": …, "email": …,}
![Page 52: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/52.jpg)
The more successful your company is, the more people
…
The more people, the more views
![Page 53: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/53.jpg)
With documental dbs it's magically easy to add new fields to your collections.
![Page 54: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/54.jpg)
Soon you might end up with{
"_id": ObjectId("123"),
"username": "Flash",
"city": …,
"phone": …,
"email": …,
"created_at": …,
"updated_at": …,
"ever_tried_to_purchase_something": …,
"canceled_at": …,
"acquisition_channel": …,
"terminated_at": …,
"latest_purchase_date": …,
…
}
![Page 55: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/55.jpg)
A bomb waiting to detonate
It’s impossible to keep adding state changes to your documents and then expect to be able to extract them with
a single query.
![Page 56: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/56.jpg)
Exploring Tools
![Page 57: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/57.jpg)
Event Store
● Engineered for event sourcing● Supports projections● By the father of CQRS (Greg Young)● Great performanceshttp://geteventstore.com/
The badBased on Mono, still too unstable.
![Page 58: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/58.jpg)
LevelWHEN
An event store built with Node.js and LevelDB● Faster than light● Completely custom, no tools to handle
aggregates
https://github.com/gabrielelana/levelWHEN
![Page 59: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/59.jpg)
The known path
● PHP (any other language would just do fine)
● MongoDB 2.2.x
![Page 60: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/60.jpg)
Why MongoDB
Events are not relational
Scales well
Awesome aggregation framework
![Page 61: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/61.jpg)
Hands on
![Page 62: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/62.jpg)
Storing Events
![Page 63: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/63.jpg)
Service |
\ |
\ [event payload] |
\ |
Service --- Queue System <------------> API -> MongoDB
/ |
/ [event payload] |
/ |
Service |
The write architecture
![Page 64: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/64.jpg)
Queues
Recruiter - https://github.com/gabrielelana/recruiter
![Page 65: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/65.jpg)
MongoDB replica set
A MongoDB replica set with two logical dbs:
1. Event store where we would store events2. Reporting DB where we would store
aggregates and final reports
![Page 66: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/66.jpg)
Anatomy of an event 1/2{ '_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9', 'type': 'an-event-type', 'data': { 'meta' : { … }, 'payload' : { … } }}
![Page 67: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/67.jpg)
Anatomy of an event 2/2'meta' : { 'creation_date': ISODate("2014-21-11T00:00:01Z"), 'saved_date': ISODate("2014-21-11T00:00:02Z"), 'source': 'some-bounded-context', 'correlation_id': 'a-correlation-id'},'payload' : { 'user_id': '1234', 'animal': 'unicorn', 'colour': 'pink', 'purchase_date': ISODate("2014-21-11T00:00:00Z"), 'price': '20/fantaeuros'}
![Page 68: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/68.jpg)
Don’t trust the network: Idempotence{
'_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9',
…
}
The _id field is actually defined client side and ensures idempotence if an event is received two times
![Page 69: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/69.jpg)
Indexes
● Events collection is huge (~100*N documents)
● Use indexes wisely as they are necessary yet expensive
● With suggested event structure:{‘data.meta.created_at’: 1, type:1}
![Page 70: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/70.jpg)
Benchmarking
How many events/second can you store?
Our machines were able to store roughly 150 events/sec. This number can be greatly increased with dedicated IOPS, more aggressive inserting policies, etc...
![Page 71: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/71.jpg)
Final tips
● Use SSD on your storage machines
● Pay attention to write concerns (w=majority)
● Test your replica set fault tolerance
![Page 72: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/72.jpg)
From eventsto meaningful metrics
![Page 73: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/73.jpg)
Sequential Projector -> Event Mapper -> Projection -> Aggregation
The event processing pipeline
![Page 74: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/74.jpg)
A real life problem
What is the conversion rate of our registered users?
![Page 75: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/75.jpg)
#1 The registration event{
'_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9',
'type': 'user-registered',
'data': {
'meta' : {
'save_date': ISODate("2014-21-11T00:00:09Z"),
'created_at': ISODate("2014-21-11T00:00:01Z"),
'source': 'core-domain',
'correlation_id': 'user-123456'
},
'payload' : {
'user_id': 123,
'username': 'flash',
'email': '[email protected]',
'country': 'IT'
}
}
}
![Page 76: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/76.jpg)
#2 The purchase event{
'_id' : '3318c11e-fe60-4c80-a2b2-7add681492d9',
'type': 'user-purchased',
'data': {
'meta' : {
'save_date': ISODate("2014-21-11T00:10:09Z"),
'created_at': ISODate("2014-21-11T00:10:01Z"),
'source': 'payment-gateway',
'correlation_id': 'user-123456'
},
'payload' : {
'user_id': 123,
'email': '[email protected]',
'amount': 20,
'value': EUR,
'payment': 'credit_card',
'item': 'fluffy cat'
}
}
}
![Page 77: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/77.jpg)
Sequential projector 1/2
[]->[x]->[]->[x]->[]->[]->[]->[]
|--------------| |------------|
|
|
|
|
---> Projector
Divides the stream of events into batches, filters events by type and pass those of interest to the mapper
![Page 78: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/78.jpg)
Sequential projector 2/2
● It’s a good idea to select fixed sizes batches to avoid memory problems when you load your Cursor in memory
● Could be a long-running process selecting events as they arrive in realtime
![Page 79: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/79.jpg)
Event mapper 1/3
Translates event fields to the Read Model domain
Takes an event as input, applies a bunch of logic and will return a list of Read Model fields.
![Page 80: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/80.jpg)
Event mapper 2/3
Input event:user-registered
Output:$output = [
'user_id' => 123, // simply copied
'user_name' => 'flash', // simply copied
'email' => '[email protected]', // simply copied
'registered_at' => "2014-21-11T00:00:01Z" // From the data.meta.created_at event field
];
![Page 81: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/81.jpg)
Event mapper 3/3
Input event:user-purchased
Output:$output = [
'user_id' => 123, // simply copied
'email' => '[email protected]', // simply copied
'purchased_at': "2014-21-11T00:10:01Z" // From the data.meta.created_at event field
];
![Page 82: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/82.jpg)
Projection
Essentially it is your read model.The data that the business is interested in.
![Page 83: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/83.jpg)
The Projection after event #1
db.users_conversion_rate_projection.findOne()
{
'user_id': 123,
'user_name': 'flash',
'email': '[email protected]',
'registered_at': "2014-21-11T00:00:01Z"
}
![Page 84: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/84.jpg)
The Projection after event #2
{
'user_id': 123,
'user_name': 'flash',
'email': '[email protected]',
'registered_at': "2014-21-11T00:00:01Z"
'purchased_at': "2014-21-11" // Added this field and rewrote others
}
![Page 85: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/85.jpg)
The Projection collection{
'user_id': 123,
'user_name': 'flash',
'email': '[email protected]',
'registered_at': "2014-21-11",
'purchased_at': "2014-21-11" // Added this field and rewrote others
}
{
'user_id': 456,
'user_name': 'batman',
'email': '[email protected]',
'registered_at': "2014-21-11",
'purchased_at': "2014-21-11" // Added this field and rewrote others
}
{
'user_id': 789,
'user_name': 'superman',
'email': '[email protected]',
'registered_at': "2014-21-12",
'purchased_at': "2014-21-12" // Added this field and rewrote others
}
![Page 86: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/86.jpg)
The Projection - A few thoughts
Note that we didn't copy from events to projection all the available fields. Just relevant ones.
![Page 87: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/87.jpg)
From these two events we could have generated infinite read models such as
● List all purchased products and related amounts for the company buyers
● Map all sales and revenues for our accounting dept
● List transactions for the financial department
![Page 88: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/88.jpg)
One way to write,infinite ways to read!
![Page 89: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/89.jpg)
The aggregation (1) - Total registered users
var registered = db.users_conversion_rate_projection.aggregate([
{
$match: {
"registered_at": { $gte: ISODate("2015-11-21"), $lte: ISODate("2015-11-22") }
}
},
{
$group: {
_id: { },
count: { $sum:1 }
}
}
]);
![Page 90: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/90.jpg)
The aggregation (2) - User with a purchase
var purchased = db.users_conversion_rate_projection.aggregate([
{
$match: {
"registered_at": { $gte: ISODate("2015-11-21"), $lte: ISODate("2015-11-22") },
"purchased_at": { $exists: true }
}
},
{
$group: {
_id: { },
count: { $sum:1 }
}
}
]);
![Page 91: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/91.jpg)
The aggregation (3) - Automate all the things
● You can easily create the aggregation framework statement by composition abstracting the concept of Column.
● This way you can dynamically aggregate your projections on (for example) an API requests.
● If your Projector is a long running process, your projections will be updated to the second and you automagically get realtime data.
![Page 92: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/92.jpg)
Another events usage:Business & Tech Monitoring
![Page 93: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/93.jpg)
Beware of the beast!No Silver Bullet
![Page 94: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/94.jpg)
Events are expensiveThey require a lot of TIME to be parsed
![Page 95: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/95.jpg)
Events are expensiveYou will end up with this billion size collection
(and counting)
![Page 96: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/96.jpg)
Fixing wrong events is painful
![Page 97: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/97.jpg)
Events are complex
![Page 98: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/98.jpg)
Moving around events is horribly painful
![Page 99: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/99.jpg)
Actually it will make your life incredibly difficult with hidden bugs and leaking
documentation.
Mongo won’t help you
![Page 100: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/100.jpg)
Improvements
● Upgrade from MongoDB 2.2.x to 3.0.x● Switch to WiredTiger storage engine to save
space
![Page 101: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/101.jpg)
Credits
Based on a talk by Jacopo Nardiello
● Slides: http://bit.ly/es-nardiello-2014 ● Video: https://vimeo.com/113370688
![Page 102: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/102.jpg)
Q&A
![Page 103: CQRS and Event Sourcing with MongoDB and PHP](https://reader036.vdocument.in/reader036/viewer/2022082218/55b6e47cbb61eb5a268b48b0/html5/thumbnails/103.jpg)
@SbiellONE — about.bellettini.me
Thank you!