使用$ lookup进行MongoDB聚合会限制从查询返回的某些字段

Sam*_*ire 25 lookup mongodb aggregation-framework

在mongo中,在执行aggregationwith之后$lookup,我希望请求只返回一些字段而不是整个文档.

我有以下查询:

db.somecollection.aggregate([{
    $lookup: {
        from: "campaigns",
        localField: "campId",
        foreignField: "_id",
        as: "campaign"
    }
}, {
    $unwind: "$campaign"
}, {
    $lookup: {
        from: "entities",
        localField: "campaign.clientid",
        foreignField: "_id",
        as: "campaign.client"
    }
}]);
Run Code Online (Sandbox Code Playgroud)

此请求将返回此信息:

{
"_id" : ObjectId("56cc7cd1cc2cf62803ebfdc7"),
"campId" : ObjectId("56c740e4479f46e402efda84"),
"articleId" : ObjectId("56c742c06094640103ba3843"),
"campaign" : {
    "_id" : ObjectId("56c740e4479f46e402efda84"),
    "clientid" : ObjectId("56c740b8479f46e402efda83"),
    "client" : [
        {
            "_id" : ObjectId("56c740b8479f46e402efda83"),
            "username" : "someusername",
            "shhh" : "somehashedpassword",
            "email" : "mail@mail.com",
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

该请求运行良好,但我想过滤字段campaign.client只能得到例如_idusername.有没有办法在MongoDB aggregate请求中执行此操作?

小智 46

只是为了帮助其他人,@ SiddhartAjmera有正确的答案,我只需要为"campaign.clientid"这样的嵌套值添加双引号.

最终的代码应该是:

db.somecollection.aggregate([
      {
        "$lookup": {
          "from": "campaigns",
          "localField": "campId",
          "foreignField": "_id",
          "as": "campaign"
        }
      },
      {
        "$unwind": "$campaign"
      },
      {
        "$lookup": {
          "from": "entities",
          "localField": "campaign.clientid",
          "foreignField": "_id",
          "as": "campaign.client"
        }
      },
      {
        "$project": {
          "_id": 1,
          "campId": 1,
          "articleId": 1,
          "campaign._id": 1,
          "campaign.clientid": 1,
          "campaign.client._id": 1,
          "campaign.client.username": 1
        }
      }
]);
Run Code Online (Sandbox Code Playgroud)

  • @Faisal它会将广告系列作为一个数组返回,如果你不做$ unwind (7认同)
  • 为什么我们添加$ unwind?为什么需要它? (2认同)

Kau*_*era 8

使用pipeline$project内部$lookup

db.somecollection.aggregate([{
    $lookup: {
        from: "campaigns",
        localField: "campId",
        foreignField: "_id",
        as: "campaign"
    }
}, {
    $unwind: "$campaign"
}, {
    $lookup: {
        from: "entities",
        let: { client_id: "$campaign.clientid" },    
        pipeline : [
            { $match: { $expr: { $eq: [ "$_id", "$$client_id" ] } }, },
            { $project : { _id:1, username:1 } }
        ],
        as: "campaign.client"
    }
}]);
Run Code Online (Sandbox Code Playgroud)


小智 5

只是在前面的答案中添加一点:您可以将 0 放入您想要忽略的项目项中,其余的将被检索,因此您不需要将所有列表写入 1:

\n
db.somecollection.aggregate([\n  {\n    "$lookup": {\n      "from": "campaigns",\n      "localField": "campId",\n      "foreignField": "_id",\n      "as": "campaign"\n    }\n  },\n  {\n    "$unwind": "$campaign"\n  },\n  {\n    "$lookup": {\n      "from": "entities",\n      "localField": "campaign.clientid",\n      "foreignField": "_id",\n      "as": "campaign.client"\n    }\n  },\n  {\n    "$project": {\n      "campaign.client.shhh": 0\n    }\n  }\n])\n
Run Code Online (Sandbox Code Playgroud)\n


小智 5

我知道现在回答这个问题已经很晚了。但在我看来,更新有时会被证明是非常有益的。
项目舞台很棒,但您仍然需要舞台上的整个码头$lookup。这些字段仅在其后的投影阶段中被过滤。

MongoDB 3.6 发布后,您现在可以向$lookup阶段添加管道,以指定多个连接条件。在他们的官方文档中查找更多详细信息。
使用 $lookup 指定多个连接条件

您可以按如下方式转换聚合管道,以获得所需的结果:

db.somecollection.aggregate([{
    $lookup: {
        from: "campaigns",
        localField: "campId",
        foreignField: "_id",
        as: "campaign"
    }
}, {
    $unwind: "$campaign"
}, {
    $lookup: {
        from: "entities",
        let: {clientid: '$campaign.clientid'},
        pipeline: [
           { '$match': 
             { '$expr': 
               { 
                  '$eq': ['$_id', '$$clientid']   
               }
             }
           },
           { '$project': 
              '_id': 1,
              'username': 1
           }
        ]
        as: "campaign.client"
    }
}]);
Run Code Online (Sandbox Code Playgroud)

这样您就可以在舞台内过滤已连接集合的字段$lookup
注意内部管道阶段$$内的标志。$match它用于表示let块内定义的自定义字段。