【问题标题】:Mongoose Aggregation with group gets rid of list orderMongoose Aggregation with group 摆脱了列表顺序
【发布时间】:2022-01-20 01:32:20
【问题描述】:

我有 2 个收藏。

Collection Name: chats
Chat {
     _id : Object(Id)
     mssg : string
     room : Object Ref (room _id)
     creationDate: DateTimeStamp
}

Collection Name: rooms
Room {
     _id : Object(Id)
     chatMssgs: [Object Ref (Chat_id_1), Object Ref (Chat_id_2), Object Ref (Chat_id_x)]
     roomName: string
     creationDate: DateTimeStamp
}

我正在尝试使用猫鼬聚合管道按最新聊天消息的顺序对房间进行排序。为此,我正在执行以下操作:

  1. 按最新聊天消息排序(使用创建日期)
  2. 使用 Lookup 获取聊天 mssg 的引用房间
  3. 展开生成的房间数组
  4. 使用 replaceRoot 将房间数组结果作为数组中的主要对象。
  5. 返回唯一的房间列表,而不会丢失最新聊天消息日期的排序。

到目前为止,以下代码可以运行到第 4 点。

await Chat.aggregate([
     {$sort: {creationDate: -1}},
     {$lookup: {
                from: "rooms",
                localField: "room",
                foreignField: "_id",
                as: "chat_room"
               }
      },
      {$unwind: "$chat_room"},
      {$replaceRoot: {newRoot: "$chat_room"}},
])

这就是我迷路的地方。如果我保持当前聚合代码不变,它可以工作,但我的房间 ID 有重复。这是因为一个房间可以有多个聊天消息。如果我在 replaceRoot 之后使用 $group,我的排序就会消失,并且最新聊天消息的顺序也会丢失。

理想情况下,我会尝试按最后的聊天消息对房间进行排序。我使用聚合,因为我还需要使用 addField 对房间后记执行一些计数,并且我为此查询使用分页,因此需要偏移和限制以保持查询相对较快。

按降序返回包含最新聊天消息的房间的最佳方式是什么? 所以房间 1 将有最新的 mssg,房间 2,... 等等,直到房间 x 显示最早发布的 mssg。

更新:在第一次回复中尝试了建议的解决方案后,我得到:

[
  {
    "_id": 3,
    "creationDate": ISODate("2014-01-03T08:00:00Z"),
    "mssg": "ghi",
    "room": 2
  },
  {
    "_id": 2,
    "creationDate": ISODate("2014-01-02T08:00:00Z"),
    "mssg": "def",
    "room": 1
  }
]

这也是我在使用方法时遇到的问题。如何让输出看起来像这样?

[
      {
        "_id": 2,
         "roomName": "room 2"
        "creationDate": ISODate("2014-01-01T08:00:00Z"),
        "chatMssgs": [3 ],
      },
      {
        "_id": 1,
        "roomName": "room 1"
        "creationDate": ISODate("2014-01-01T08:00:00Z"),
        "chatMssgs": [1,2 ],
      }
    ]

【问题讨论】:

    标签: mongodb mongoose graphql


    【解决方案1】:

    找到最大日期,然后过滤它。

    db.chats.aggregate([
      {
        "$match": {
          _id: {
            "$in": [
              1,
              2,
              3
            ]
          }
        }
      },
      {
        "$group": {
          "_id": "$room",
          "latestMsgDate": {
            "$max": "$creationDate"
          },
          "Msg": {
            $push: "$$ROOT"
          }
        }
      },
      {
        "$set": {
          "Msg": {
            "$filter": {
              "input": "$Msg",
              "as": "m",
              "cond": {
                "$eq": [
                  "$$m.creationDate",
                  "$latestMsgDate"
                ]
              }
            }
          }
        }
      },
      {
        "$replaceRoot": {
          "newRoot": {
            "$first": "$Msg"
          }
        }
      },
      {
        "$sort": {
          creationDate: -1
        }
      }
    ])
    

    mongoplayground

    【讨论】:

    • 谢谢。我会测试一下。如果我只想返回房间数据(仅限房间文档)而不是与聊天 mssgs 相关的任何内容。我基本上想按顺序列出在屏幕上最早有最新消息的房间。所以返回应该反映房间集合。
    【解决方案2】:

    好的。感谢 YuTing 的回答,我能够得到我想要的东西(请参阅有问题的更新部分)。对于任何感兴趣的人:

       db.chats.aggregate([
          {$lookup: {
              from: "rooms",
              localField: "room",
              foreignField: "_id",
              as: "chat_room",
            },
          },
        { $group: {
           _id: "$chat_room",
           latestMsgDate: { $max: "$creationDate" },
           },
         },
        {$sort: { latestMsgDate: -1 }},
    {$unwind: "$_id"},
    {$replaceRoot: { newRoot: "$_id" }}
        ])
    

    您可以在mongoplayground 进行测试。输出是:

    [
      {
        "_id": 2,
        "chatMssgs": [
          3
        ],
        "creationDate": ISODate("2014-01-01T08:00:00Z"),
        "roomName": "room 2"
      },
      {
        "_id": 1,
        "chatMssgs": [
          1,
          2
        ],
        "creationDate": ISODate("2014-01-01T08:00:00Z"),
        "roomName": "room 1"
      }
    ]
    

    【讨论】:

    • 干得好,如果我的回答也被赞成或接受,那就太好了。
    猜你喜欢
    • 2011-12-30
    • 2020-06-17
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 2010-10-01
    • 2023-04-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多