带组的猫鼬聚合摆脱了列表顺序
Mongoose Aggregation with group gets rid of list order
我有2个collections.
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
}
我正在尝试使用 mongoose 聚合管道按最新聊天消息的顺序对房间进行排序。为此,我正在执行以下操作:
- 按最新聊天消息排序(使用创建日期)
- 使用 Lookup 获取聊天 mssg 的参考房间
- 展开结果的房间数组
- 使用 replaceRoot 将房间数组结果作为数组中的主要 objects。
- Return 独特的房间列表,不会丢失最新聊天消息日期的排序。
到目前为止,以下代码可以运行到第 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 对房间后记执行一些计数,并且我对此查询使用分页,因此需要偏移量和限制来保持查询速度相对较快。
return 聊天室最新聊天消息降序排列的最佳方式是什么?
所以房间 1 将有最新的消息,房间 2,...等直到房间 x 显示最早发布的消息。
更新:尝试第一个回复中建议的解决方案后,我得到:
[
{
"_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 ],
}
]
找到 max 日期,然后 filter 它。
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
}
}
])
好的。感谢 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"
}
]
我有2个collections.
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
}
我正在尝试使用 mongoose 聚合管道按最新聊天消息的顺序对房间进行排序。为此,我正在执行以下操作:
- 按最新聊天消息排序(使用创建日期)
- 使用 Lookup 获取聊天 mssg 的参考房间
- 展开结果的房间数组
- 使用 replaceRoot 将房间数组结果作为数组中的主要 objects。
- Return 独特的房间列表,不会丢失最新聊天消息日期的排序。
到目前为止,以下代码可以运行到第 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 对房间后记执行一些计数,并且我对此查询使用分页,因此需要偏移量和限制来保持查询速度相对较快。
return 聊天室最新聊天消息降序排列的最佳方式是什么? 所以房间 1 将有最新的消息,房间 2,...等直到房间 x 显示最早发布的消息。
更新:尝试第一个回复中建议的解决方案后,我得到:
[
{
"_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 ],
}
]
找到 max 日期,然后 filter 它。
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
}
}
])
好的。感谢 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"
}
]