要实现这一目标,您需要首先unwind
评论,然后使用group
有一个小技巧。如果您想省略_id
,那么您还需要做一个简单的项目。这是完整的聚合管道:
db.posttest.aggregate([
{ $unwind : "$comments" },
{ $group : {
_id : "$_id",
username : { $first : "$username" },
text : { $first : "$text" },
comments : { $push : "$comments" },
hasComments : { $max : { $eq : [ "$comments.username", "User1" ] } }
}},
{ $project : { _id : false } }
])
解释如下。
首先,我们需要删除一个数组(comments
)。为此,我们展开记录;它给了我们四个记录:
{
"_id" : 21353456,
"username" : "xy",
"text" : "asdf",
"comments" : {
"username" : "User1",
"text" : "hi"
}
},
{
"_id" : 21353456,
"username" : "xy",
"text" : "asdf",
"comments" : {
"username" : "User2",
"text" : "hi1"
}
},
{
"_id" : 21353456,
"username" : "xy",
"text" : "asdf",
"comments" : {
"username" : "User3",
"text" : "hi2"
}
},
{
"_id" : 21353456,
"username" : "xy",
"text" : "asdf",
"comments" : {
"username" : "User4",
"text" : "hi3"
}
}
现在我们可以将所有记录分组为一个,对每个字段应用一个函数。首先,我们需要给出标准,即“分组依据”字段(或字段集)。在我们的例子中,它只是 id:_id: "$_id"
.
然后,对于每个字段,我们需要决定如何将其包含到结果记录中。我们有几个字段:username
, text
, and comments
。对于每四个记录,用户名和文本都是相同的,因此我们可以轻松选择其中任何一个,即$first
or $last
.
comments
然而,情况有所不同。我们希望保护所有这些,以便我们$push
各一回来。
The hasComments
这里有点棘手:我们需要检查是否至少有一个comment.username
包含用户名。我们可以用$eq: [...]
在这里,它会给我们一些数组,例如[true, false, false, false]
or [false, false, true, false]
。我们需要选择将哪个值放入结果记录中。在这种情况下,我们不能使用$first
nor $last
。然而,$max
会给我们一个合适的结果。