我有一个嵌套的嵌入式文档,看起来像这样。每个帖子都有n条评论,每条评论都有用户详细信息,包括姓名和电子邮件ID。
我只想将评论用户的姓名投射到列表中
{
"PostId":"Post001",
"Comments":[
{"_id": "001",
"CommentedBy":{
"_id":"User001",
"Name":"UserName001",
"email":"user001@eg.com"
}
},
{"_id": "002",
"CommentedBy":{
"_id":"User002",
"Name":"UserName002",
"email":"user001@eg.com"
}
},
{"_id": "003",
"CommentedBy":{
"_id":"User003",
"Name":"UserName003",
"email":"user001@eg.com"
}
}
]
}
我想通过使用mongodb的聚合管道转换为类似如下的内容。
{
"PostId":"Post001"
"Comments":[
{"_id": "001",
"CommentedBy":"UserName001",
},
{"_id": "002",
"CommentedBy": "UserName002"
},
{"_id": "003",
"CommentedBy": "UserName003"
}
]
}
使用mongo的投影查询可提供CommentedBy
的列表以及所有名称。 如何使用mongo的汇总查询实现这一目标。有没有一种方法可以不使用$unwind
。
我尝试过的查询和得到的结果。
db.getCollection('post').aggregate([
{$project:{"Comments.CommentedBy":"$Comments.CommentedBy.Name"}}
])
{
"_id" : ObjectId("5b98b4cc3bb8c65aeacabd78"),
"Comments" : [
{
"CommentedBy" : [
"UserName001",
"UserName002",
"UserName003"
]
},
{
"CommentedBy" : [
"UserName001",
"UserName002",
"UserName003"
]
},
{
"CommentedBy" : [
"UserName001",
"UserName002",
"UserName003"
]
}
]
}
答案 0 :(得分:3)
您可以尝试使用$map
聚合,并且可以通过遍历Comments
数组来更改内部的键。
db.collection.aggregate([
{ "$project": {
"PostId": 1,
"Comments": {
"$map": {
"input": "$Comments",
"as": "comment",
"in": {
"_id": "$$comment._id",
"CommentedBy": "$$comment.CommentedBy.Name"
}
}
}
}}
])
答案 1 :(得分:1)
您可以先计划要做的事情。例如。您可以尝试以下方法:
因此阶段将是:
const unwind = {
$unwind: '$Comments',
};
这导致将文档复制(或更确切地说,就是将其复制)成与注释相同的数量。
现在,project根据需要添加评论者姓名/ ID:
const project = {
$project: {
PostId: 1,
CommentId: '$Comments._id',
CommentedBy: '$Comments.commentedBy.Name',
},
}
现在,对于每个评论,您都有一个文档:{ PostId, CommentId, CommentedBy }
。
现在,您可以group返回您的评论,并按PostId
进行分组:
const group = {
$group: {
_id: '$PostId',
PostId: '$PostId',
Comments: {
$push: {
_id: '$CommentId',
CommentedBy: '$CommentedBy',
},
},
},
};
您现在将获得这样的文档:
{
_id: '<PostID>',
PostId: '<PostID>',
Comments: [
{ _id: '<CommentId>', CommentedBy: '<username>' },
],
}
您会注意到,您在那里还有一个额外的顶级_id
,可以在另一个$project
阶段摆脱它:
const cleanup = { $project: { _id: 0, ... } };
所以您的整个管道现在很简单:
db.getCollection('posts')
.aggregate([
unwind,
project,
group,
cleanup,
]);
我省略了一些样板,并且我在这里没有MongoDB进行键入,因此您可能需要仔细检查代码。 (不过,您可能还是要使用internetz的代码来完成此操作。)
答案 2 :(得分:0)
unwind
注释,然后project
和PostId group
将所有注释推入数组。
db.getCollection('test').aggregate([
{"$unwind" : "$Comments"},
{$project:{
"PostId":"$PostId",
"Comments.CommentedBy":"$Comments.CommentedBy.Name",
"Comments._id" : "$Comments.CommentedBy._id"
}
},
{"$group" : {
_id: "$PostId",
//Comments: { "$push" : {"_id" : "$Comments._id", "CommentedBy" : "$Comments.CommentedBy"}} If you want to push specifi field.
Comments: { "$push" : "$Comments"} // Only push whole Comments object will also work.
}
}
])
输出:
{
"_id" : "Post001",
"Comments" : [
{
"_id" : "User001",
"CommentedBy" : "UserName001"
},
{
"_id" : "User002",
"CommentedBy" : "UserName002"
},
{
"_id" : "User003",
"CommentedBy" : "UserName003"
}
]
}
如果要推送特定字段。
Comments: { "$push" : {"_id" : "$Comments._id", "CommentedBy" : "$Comments.CommentedBy"}}
或整个对象
Comments: { "$push" : "$Comments"}