php editor Youzi will introduce you to a common operation in this article - aggregation, that is, inserting data from one collection into another collection. Aggregation operations are very common in programming and can be used in various scenarios such as merging data, deduplication, and filtering. Through aggregation operations, we can easily process and manage data, improving the efficiency and readability of the code. Next, we will introduce the use and precautions of aggregation operations in detail to help everyone better master this technique.
I'm trying to do the following to get the list of chats from a specific user's chat
collection and send the message
collection The last message in is added to this list for each chat.
Now how this works, I have two methods as described below
First, I just get the list of chats using the chat member id, the second method uses aggregation to find the last message of each chat, then I just match the message with the chat id
Favorites Chat:
type chat struct { id string `json:"id" bson:"id"` participants []string `json:"participants" bson:"participants"` lastmessage *message `json:"last_message,omitempty" bson:"last_message"` ... }
Note
lastmessage
- is always zero, I only need it to write a response for the user.
Collectionmessage
:
type message struct { id string `json:"id" bson:"id"` chatid string `json:"chat_id" bson:"chat_id"` fromid string `json:"from_id" bson:"from_id"` createdate int64 `json:"create_date" bson:"create_date"` body string `json:"body" bson:"body"` updateat int64 `json:"update_at" bson:"update_at"` ... }
First method: I need this method to get the active chat list of a specific chat participant.
func activechats(ctx context.context, uid string) ([]*chat, error) { ... filter := bson.d{primitive.e{key: "participants", value: uid}} cursor, err := r.col.find(ctx, filter, nil) if err != nil {...} var ch []*chat if err = cursor.all(ctx, &ch); err != nil {...} if err = cursor.close(ctx); err != nil {...} ... }
Second method: I need this method to get the last message of each chat, the input is a set of chat ids, and for each chat I search for the last message (if there is ). For this I use aggregation.
func lastmessages(ctx context.context, chatids []string) (map[string]*message, error) { matchstage := bson.d{ primitive.e{ key: "$match", value: bson.d{ primitive.e{ key: "chat_id", value: bson.d{ primitive.e{key: "$in", value: chatids}, }, }, }, }} sortstage := bson.d{primitive.e{key: "$sort", value: bson.d{primitive.e{key: "created", value: -1}}}} groupstage := bson.d{primitive.e{ key: "$group", value: bson.d{ primitive.e{ key: "_id", value: bson.d{ primitive.e{key: "chat_id", value: "$chat_id"}, }, }, primitive.e{ key: "message", value: bson.d{ primitive.e{key: "$first", value: "$$root"}, }, }, }, }} cursor, err := r.colmessage.aggregate(ctx, mongo.pipeline{matchstage, groupstage, sortstage}) if err != nil {...} var res []*aggregationresultgenerated if err = cursor.all(ctx, &res); err != nil {...} ... }
I know this is a really bad solution, but this is all I can think of so far and it's a shame (doesn't work). I try to solve this problem
db.chat.aggregate([ { $match: { participants: "participant_id", }, { $lookup: { from: "message", // other table name localfield: "id", // name of chat table field foreignfield: "chat_id", // name of message table field as: "msg", } }, { $unwind: "$msg", }, { $match: { chat_id : { $in: ["$$root._id"], }, }, }, { $sort: { "created": -1, }, }, { $group: { "_id": { "chat_id": "$chat_id" }, "doc": { "$last": "$$root" } } }, { $project: { last_message: "$msg", } } ])
My question is: How to use aggregation to get a list of chats for a specific user and for each chat add the last message in the field last_message in the object chat
from the message
collection information?
How it works now:
{ "chats": [ { "id": "4hWsHam3ZZpoyIw44q3D", "title": "Chat example", "create-date": 1674476855918, "participants": [ "63ce54460aeee5e72c778d90", "63ce54460aeee5e72c778d92" ], "owner_id": "63ce54460aeee5e72c778d90", "last_message": { "id": "tzwekCiCLSXJ4tfdQuHH", "chat_id": "4hWsHam3ZZpoyIw44q3D", "from_id": "63ce54460aeee5e72c778d92", "create_date": 1674557062031, "body": "text", "update_at": 0, "viewed": false }, "unread": 5 }, { "id": "Anjrr9RCWFzq030Cwz7S", "title": "New chat One", "create-date": 1674476909054, "participants": [ "63ce54460aeee5e72c778d90", "63ce54460aeee5e72c778d96" ], "owner_id": "63ce54460aeee5e72c778d90", "last_message": { "id": "7YqhhS1-EfMRSZtGCH0Z", "chat_id": "Anjrr9RCWFzq030Cwz7S", "from_id": "63ce54460aeee5e72c778d96", "create_date": 1674575017115, "body": "text", "update_at": 0, }, "unread": 1 }, ] }
Edit: As the OP mentioned in the comments, update/$merge
to the collection is not necessary.
You can simply execute the $sort
$limit
method in a sub-pipeline of $lookup
. Execute $unwind
to write the search results into the last_message
field. Finally, execute $merge
to update back the chat
collection.
db.chat.aggregate([ { $match: { participants: "63ce54460aeee5e72c778d90", } }, { $lookup: { from: "message", localField: "id", foreignField: "chat_id", pipeline: [ { $sort: { created: -1 } }, { $limit: 1 } ], as: "last_message", } }, { $unwind: { path: "$last_message", preserveNullAndEmptyArrays: true } }, { $project: { last_message: "$last_message" } } ])
Here is an old mongo playground updated with $merge
to a collection.
The above is the detailed content of Aggregation, inserting data from one collection into another collection. For more information, please follow other related articles on the PHP Chinese website!