Aggregation, inserting data from one collection into another collection

王林
Release: 2024-02-10 23:30:19
forward
722 people have browsed it

Aggregation, inserting data from one collection into another collection

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.

Question content

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"`
    ...
}
Copy after login

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"`
    ...
}
Copy after login

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 {...}
    ...
}
Copy after login

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 {...}
    ...
}
Copy after login

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",
        }
    }
])
Copy after login

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
        },
    ]
}
Copy after login

Workaround

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"
    }
  }
])
Copy after login

mongo playground

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!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!