How do I change the read model in cqrs? - events

I'm new in cqrs user.
I have event in
id agg event payload time
1 member MemberCreated {id:1,user:yumi,age:21 ...} 2021-06-10
2 member MemberUpdated {id:1,user:yumi,age:25 ...} 2021-06-10
3 member MemberDeleted {} 2021-06-11
and, my ask is
How does the read model change based on events 1-3 above?
first scenario :
1 event in readmodel :
{id:1,user:yumi,age:21 ...}
1 row in readmodel
2 event in readmodel :
{id:1,user:yumi,age:21 ...}
{id:1,user:yumi,age:25 ...}
2 row in readmodel
3 event in readmodel :
{id:1,user:yumi,age:21 ...}
{id:1,user:yumi,age:25 ...}
{}
3 row in readmodel
or update only read model ??
second scenario :
{id:1,user:yumi,age:21 ...}
->
{id:1,user:yumi,age:25 ...}
->
{}
I am very confused about this issue. Any help would be appreciated.

Please note, that your events are always related to some DDD aggregate with an ID, so there should be an aggregateID column in your event table.
The answer depends on what do you want to have in your read model. For instance if you want to have some Members table with a row for each member, then in pseudocode I would do it like this:
switch(e.event) {
case MemberCreated:
db.Insert(Members, {
id: event.aggregateID,
user: e.payload.user,
age: e.payload.age}
)
break
case MemberUpdated:
db.Update(Members, {
id: event.aggregateID,
user: e.payload.user,
age: e.payload.age}
)
break
case MemberDeleted:
db.Delete(Members, {id: event.aggregateID})
break
}
But if you want to have some MemberCount table with number of members, you would increment it on MemberCreated and decrement on MemberDeleted.
If you want to have an AuditLog table, then you would just add a row about what happened on each event.

Related

Laravel Eloquent: Count Rows and group them by the day

I have a Model called "AdInteraction", these interactions can either be a click or a view (They either have boolean clicked or boolean viewed set to true).
Along every Interaction I save the created_at date.
Now this is what I want to end up with in order to have all the data I need to populate a ChartJS Chart:
[
{
"date": "01-01-2018"
"clicks": 13,
"views": 25
},
{
"date": "02-01-2018"
"clicks": 25,
"views": 74
},
{
"date": "03-01-2018"
"clicks": 0,
"views": 0
},
]
This is a query I already got on my Ad model which is related to AdInteraction:
public function getClicksForLastDays()
{
return $this->clicks()->get()->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('y-m-d');
});
}
However this returns me an array of arrays looking like this:
What would be the correct and most efficient way to fetch the clicks and count them by days?
try this and let me know, I assume your column names are date,clicks,views, if its different then pls let me know, so I will adjust the answer or you can do it your self..
AdInteraction::select([DB::raw('DATE(date)'),DB::raw('count(case when clicks ="true" then 1 end) as "Clicks"'),
DB::raw('count(case when views ="true" then 1 end) as "Views"')])
->groupBy(DB::raw('DATE(date)'))
->get();
or try this
AdInteraction::select([DB::raw('DATE(date)'),DB::raw('count(case when clicks =true then 1 end) as "Clicks"'),
DB::raw('count(case when views =true then 1 end) as "Views"')])
->groupBy(DB::raw('DATE(date)'))
->get();
You should consider abandoning the idea of grouping by date using datetime column since such query will be very inefficient. When you, for example, GROUP BY DATE(created_at) MySQL will be performing this cast function for each row and won't be able to utilize indexes for created_at.
Therefore I recommend you to denormalize your table by introducing separate DATE created_date_at column for created_at value and create an index for it. Then you will be able to efficiently group your stats by this new column value. Just be sure to register the following code for your model:
AdInteraction::creating(function ($adInteraction) {
$adInteraction->created_date_at = $adInteraction->created_at->format('Y-m-d');
});
Or you can consider creating separate int columns for year, month and day. Then you can create a multi-column index and group by these columns. This way you will be able to also easily retrieve stats by days, months and years if needed.

Joins in rethinkdb

I have the following data structure stored in RethinkDB table:
{
id: string,
parentId: string,
timestamp: number,
data: Object
}
This data structure forms a tree, it can be depicted using the following diagram (white records represent ordinary data carrying records, the red ones have their data property equal to null which represents delete operation):
Now for every record in the table I would like to be able to compute the nextRecord. Which is the closest record in time to the current one. The task seems simple when there is only one record pointing back to a parent:
1 => 2
4 => 9
5 => 6
6 => 8
...
But it becomes more difficult to compute such value when parent record is being referenced by several child records:
2 => 3
3 => 5
7 => 11
The is also case when there is no child reference in which case the result should be null (for example record #8 has no child records, and so null should be returned).
So I'm not asking to write the query itself (which on the other hand would be really great to me) but at least point out the direction in which I can find solution to this problem.
Thank you in advance!
You can do this efficiently with a compound index on parentId and timestamp. You can create the index like this:
r.table('data').indexCreate('parent_timestamp', function(row) {
return [row('parentId'), row('timestamp')];
})
After you've done that, you can find the earliest item with parent PARENT like so:
r.table('data')
.between([PARENT, r.minval], [PARENT, r.maxval], {index: 'parent_timestamp'})
.orderBy({index: 'parent_timestamp'})
.nth(0).default(null)

delete record related through two field

I have two models:
model 1
field id, field_a, field_b
model 2
id2, field_a, field_b
on $model1->delete() I would like to delete also $model2 where field_a and field_b are the same of $model1 (both of them)
Example
model1
1, 2, 5
model2
1, 2, 4
2, 3, 5
3, 2, 5 (to be deleted)
I don't know if this could be helpful
Automatically deleting related rows in Laravel (Eloquent ORM)
Register a delete event on model 1 that deletes model 2 where the values match.
In model 1 add the following...
public static function boot()
{
parent::boot();
static::deleted(function($model1) {
Model2::where('field_1', $model1->field_1)->where('field_2', $model1->field_2)->delete()
});
}
Now whenever you delete model 1, model 2 with matching attributes are also removed.
Just find and delete the rows from model2 where the column values are similar.
Model2::where('field_a',$model1->field_a)->where('field_b',$model1->field_b)->delete();
$model1->delete();
Here, Model2 is the class of the Second model.

Laravel - retrieve direct/indirect pivot table subscribers

I am having a hard time figuring this out in laravel; for a subscriber relationship we have 2 pivot tables:
A subscriber can subscribe to a question:
question_subscriber
id question_id subscriber_id
1 2 3
2 2 4
3 3 1
4 3 2
A subscriber can subscribe to a user:
user_subscriber
id user_id subscriber_id
1 1 6
2 1 7
3 2 1
Normal questions table with question owner:
questions
id question user_id
1 abc? 1
2 xyz? 1
3 123? 2
The pivot relationships are setup correctly in their models, and I can pull out with a foreach, subscribers for a question, $question->subscribersQuestion as $subscriber, or subscribers for a user, $user->subscribersUser as $subscriber:
But how can we pull out all subscribers that belong to a user (directly or indirectly (through a question they own))?
For example, these should be all retrieved subscribers for user 1:
6 // subscribed to directly
7 // subscribed to directly
3 // subscribed to through question
4 // subscribed to through question
Any idea on the most efficient way to do this in Laravel?
This will be the easiest way:
// assuming this setup:
User hasMany Question
User belongsToMany User (subscribers - direct)
Question belongsToMany User (subscribers - indirect)
// we don't need this, since we pass it by reference to the closure,
// but for clarity let's initialize this variable:
$indirectSubscribers = null;
$user = User::with(['questions.subscribers' => function ($q) use (&$indirectSubscribers) {
// get all indirect subscribers (cost of additional query)
$indirectSubscribers = $q->get()->unique();
}])->find($userId);
// merge with directs subscribers
$allSubscribers = $user->subscribers->merge($indirectSubscribers);

Does Eloquent relation sync also remove?

When updating a model and I sync a relationship, if I don't pass in all the ids that already exist, will that relationship be removed?
You decide: sync has 2nd parameter that defaults to true and is responsible for detaching:
$model->relationship()->sync([1,2,3]);
$model->relationship()->sync([4,5,6]); // attached [4,5,6], detached [1,2,3]
$model->relationship()->getRelatedIds(); // [4,5,6]
// but:
$model->relationship()->sync([4,5,6], false); // attached [4,5,6], detached []
$model->relationship()->getRelatedIds(); // [1,2,3,4,5,6]
The answer is Yes it does. I could not find any documentation that in fact stated that.
lets say you have 2 tables: "authors" and "books", with a pivot table "book_authors".
when creating a new author:
$author_id =2;
$author->books()->sync(array(1,4,5,15));
Now you have a 4 entries in that pivot table "book_authors":
author_id book_id
2 1
2 4
2 5
2 15
Now update:
$author_id =2;
$author->books()->sync(array(1,15));
now "book_authors" is:
author_id book_id
2 1
2 15

Resources