Reputation: 325
I've got no where to turn. I'm hoping someone here will point me in the right direction.
Every User has a Statistics row which contains their friend count, friend request count, new message count and message count. It is far quicker to select 1 row from this table as opposed to performing a large query full of joins etc just to retrieve a users statistics on every page load.
The problem here is that, that row needs to be updated on every new conversation message. This isn't really a concern if I'm just updating one row. A conversation could have multiple participants (let's take 20 for example).
I will need to update 20 rows in the statistics table. This is considered a bad idea as it will cause blocking for other users making a request. Understandable. I will need to update 20 rows in the conversation participants table (has_read flag, has_deleted flag and possibly created_at as the participant is "re-instated" to the conversation). Ok so in total I'm updating 40 rows on every new message... sounds a bit overkill but it doesn't stop there.
Updating rows in eloquent is not simple. I don't know how you can do a bulk update in eloquent either so the code ends up like this:
foreach ($conversation->participants as $participant) {
if ($participant->user_id == Auth::user()->id) {
continue;
}
$participant->has_read = 0;
if ($participant->has_deleted == 1) {
$participant->has_deleted = 0;
$participant->created_at = DB::Raw('NOW()');
}
$participant->save();
$participant->user->stats->new_messages += 1;
$participant->user->stats->save();
}
So already, I'm performing at least 40 queries. Not to mention the user itself is not eager loaded... not really sure how to eager load them in relationships so I'm performing at least 60 queries by doing it in eloquent every time a new message is sent. I don't know about you, but to me that is cringe.
So basically, I'm unsure how to handle the whole statistics side of things and bulk updating. I feel as if I'm hit a brick wall and I'm not sure what to do or where to turn. Please help, thanks.
Upvotes: 1
Views: 184
Reputation: 1361
Generally this is what is done for mass assignment:
1) Iterate over all the data and form an array of all the things that you need to update
2) While iterating, form another array of id's of the rows to be updated.
3) With these two arrays, do mass assignment using WhereIn and update of eloquent.
Something like this:
ParticipantModel::whereIn('id',$array_of_id)->update($data_to_update);
Your $data_to_update array should only contain the fields that are present in your table.
Simplifying your example, for the sake of explanation this is how you can do the above steps:
$array_of_id = array();
$data_to_update = array();
foreach ($conversation->participants as $participant) {
$array_od_id[] = $participant['id'] //Pushing the ids into the array
$participant['has_read'] = 0;
if ($participant['has_deleted'] == 1) {
$participant['has_deleted'] = 0;
$participant['created_at'] = DB::Raw('NOW()');
}
$data_to_update[] = $participant; //Pushing each participant into data_to_update
}
/* You can either use DB raw or model,if you have it */
ParticipantModel::whereIn('id',$array_of_id)->update($data_to_update);
The advantage is that now you are making only one DB query to update the data, instead of making update query for each record.
Please note that I have simplified your example. You have to figure out how you can extend this logic to accommodate your user table updates.
Upvotes: 1