MongoDB Aggregation Project检查数组是否包含

use*_*661 3 mongodb mongodb-query aggregation-framework

我有以下文件:

{
    _id : 21353456,
    username : "xy",
    text : "asdf",
    comments : [
        {
            username : "User1",
            text : "hi",
        },
        {
            username : "User2",
            text : "hi1",
        },
        {
            username : "User3",
            text : "hi2",
        },
        {
            username : "User4",
            text : "hi3",
        }

    ]
}
Run Code Online (Sandbox Code Playgroud)

现在,我想获取带有聚合和项目的用户名,文本和注释。另外,如果comments数组包含带有“ User1”的用户名,我也想使用布尔值。我有这个,但是不起作用。

db.posttest.aggregate(
   [
     {
       $project:
          {
            username: 1,
            text: 1,
            comments : 1,
            hasComment: { $eq: [ "comments.$.username", "User1" ] },
            _id: 0
          }
     }
   ]
)
Run Code Online (Sandbox Code Playgroud)

Ale*_*sov 5

为此,您需要先添加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 } }
])
Run Code Online (Sandbox Code Playgroud)

以下是解释。

首先,我们需要删除一个数组(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"
  }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以将所有记录归为一组,对每个字段应用一个函数。首先,我们需要提供标准,即“分组依据”字段(或一组字段)。在我们的例子中,它仅仅是ID: _id: "$_id"

然后,对于每个字段,我们需要决定如何将其包含到结果记录中。我们有几个字段:usernametext,和comments。对于每四个记录,用户名和文本都相同,因此我们可以轻松地选择它们中的任何一个,即$first$last

comments但是,是不同的。我们希望保留所有这些,以便我们$push每个人回来。

hasComments这里有一个小技巧:我们需要检查是否至少一个comment.username包含用户名。我们可以$eq: [...]在这里使用,它将为我们提供一些数组,例如[true, false, false, false][false, false, true, false]。我们需要选择将哪个值记入结果记录中。在这种情况下,我们既$first不能使用也不能使用$last。但是,$max会给我们适当的结果。

  • 谢谢,很好的回答! (2认同)