我正在try 执行以下操作,从特定用户的chat个集合中获取聊天列表,并 for each 聊天添加来自message集合中的最后一条发送的消息.

现在这是如何工作的,我有两个方法,它们描述如下

首先,我只使用聊天成员id获取聊天列表,第二种方法使用聚合来查找每个聊天的最后一条消息,然后将消息与聊天的id进行匹配

Collection 聊天:

type Chat struct {
    ID           string   `json:"id" bson:"id"`
    Participants []string `json:"participants" bson:"participants"`
    LastMessage  *Message `json:"last_message,omitempty" bson:"last_message"`
    ...
}

附注: LastMessage-始终为零,我只需要它来为用户 compose 响应.

Collection 集message:

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:我需要此方法来获取特定聊天参与者的活动聊天列表.

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:我需要这个方法来获取每个聊天的最后一条消息,输入是一组聊天ID,对于每个聊天ID,我都会搜索最后一条消息(如果有).为此,我使用聚合.

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 {...}
    ...
}

我知道这是一个非常糟糕的解决方案,但到目前为止,这是我能想到的唯一办法,很遗憾(不是工作).我试着解决这个问题

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

我的问题是:如何使用聚合来获得特定用户的聊天列表,并 for each 聊天添加集合message中对象chat中LAST_MESSAGE字段中的最后一条消息? 它现在是如何运作的:

{
    "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
        },
    ]
}

推荐答案

编辑:就像OP在 comments 中提到的,不需要对集合进行UPDATE/$merge.

您可以简单地在$lookup的子流水线中进行$sort+$limit方法.进行$unwind运算,将查找结果与last_message字段进行运算.最后,执行$merge以更新回chat集合.

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

Mongo Playground

这里是一个old Mongo Playground$merge更新为一个集合.

Mongodb相关问答推荐

如何在 mongodb 查找的外键中使用正则表达式

Spring Boot 升级后未映射 Mongo 模板结果

如何更新mongo中列表最后一个对象的属性

Golang:如何判断 collection.Find 是否没有找到任何文件?

mongoDB 过滤、排序和排名结果

为什么一个 mongodb 副本集需要奇数个投票 node ?

MongoDB - 如果新值更大,则更新字段

在一个变量上运行的 Node JS 中使用正则表达式的 Mongo 查询

如何将查询结果(单个文档)存储到变量中?

GeoJSON 和 MongoDB:将点存储为 GeoJSON.Point 是否值得?

Mongoose $push 不断添加两个条目

Mongodb将重音字符匹配为基础字符

MongoDB限制内存

使用 Jackson 与 Java Mongo DBObject 进行高效 POJO 映射

无法使用命令写入模式错误,降级到兼容模式

如何在mongoDB中检索其值以特定字符结尾的文档

MongoError:Can't extract geo keys from object

带有索引字段的 MongoDB 正则表达式

带有条件的MongoDB聚合查找

如何在 Windows 上停止 mongodb 服务器?