通过引用父文档中的多个值来使用 $lookup

Use $lookup by referring to multiple values in the parent document

我正在尝试 MongoDb 3.5.8 中可用的新 $lookup pipeline 功能,想知道如何从 pipeline 引用父文档中的字段。

我试图将父文档中的两个字段与查找文档中的两个字段进行比较。不知道该怎么做 {$eq : ['$input_doc.field1', '$field1'] }.

 db.input_doc.aggregate([
        {
          $lookup:
            {
              from: "foreign_doc",
              pipeline: [
                            { $project: { 'matched': { $and : [ 
                                { $eq : ["$input_doc.field1", "$field1"] }, 
                                { $eq : ["$input_doc.field2", "$field2"] } 
                                          ]} },
                            { $match : { 'matched' : true } }
              ],
              as: "as_doc"
            }
       }
    ])

谢谢

你在这里的意思不是很清楚,你可能是指使用 let 和新的 pipeline 选项,但也可能你指的是完全不同的情况。

pipeline 操作通常用于 "non-correlated" 数据检索,这在各种用例中都很有用。这与 "correlated" 数据相反,其中 localFieldforeignField 可以应用于两个集合之间的 "join"。

如前所述,DOCS-10298

中对此进行了介绍

最好举个例子。以创建这些集合为例:

db.related.insert([
  { "a": 1, "b": 2 },
  { "a": 2, "b": 2 },
  { "a": 3, "b": 3 }
])

db.parent.insert({
  "name": "test",
  "b": 2
})

我可以在这里使用 pipelinelet 语句来测试另一个集合的项目的逻辑条件,如下所示:

db.parent.aggregate([
  { "$lookup": {
    "from": "related",
    "let": {
      "b": "$b"      
    },
    "pipeline": [
      { "$addFields": {
        "matched": { "$eq": [ "$$b", "$b" ] }
      }}
    ],
    "as": "results"
  }}
])

这将给出结果:

{
        "_id" : ObjectId("595332c28965d862ce61f451"),
        "name" : "test",
        "b" : 2,
        "results" : [
                {
                        "_id" : ObjectId("59532b028965d862ce61f44d"),
                        "a" : 1,
                        "b" : 2,
                        "matched" : true
                },
                {
                        "_id" : ObjectId("59532b028965d862ce61f44e"),
                        "a" : 2,
                        "b" : 2,
                        "matched" : true
                },
                {
                        "_id" : ObjectId("59532b028965d862ce61f44f"),
                        "a" : 3,
                        "b" : 3,
                        "matched" : false
                }
        ]
}

这表明该条件已根据父文档中 let 中声明的变量与 pipeline 提供的相关集合中的声明变量进行了测试。

这样您还可以使用 "logical" 过滤器,例如 $redact:

db.parent.aggregate([
  { "$lookup": {
    "from": "related",
    "let": {
      "b": "$b"      
    },
    "pipeline": [
      { "$redact": {
        "$cond": {
          "if": { "$eq": [ "$$b", "$b" ] },
          "then": "$$KEEP",
          "else": "$$PRUNE"
        }
      }}
    ],
    "as": "results"
  }}
])

哪个returns:

{
        "_id" : ObjectId("595332c28965d862ce61f451"),
        "name" : "test",
        "b" : 2,
        "results" : [
                {
                        "_id" : ObjectId("59532b028965d862ce61f44d"),
                        "a" : 1,
                        "b" : 2
                },
                {
                        "_id" : ObjectId("59532b028965d862ce61f44e"),
                        "a" : 2,
                        "b" : 2
                }
        ]
}

但是,当然,MongoDB 3.2 中引入的现有功能以及正常的 "correlated" 选项已经涵盖了这一点:

db.parent.aggregate([
  { "$lookup": {
    "from": "related",
    "localField": "b",
    "foreignField": "b",
    "as": "results"
  }}
])

结果同上

当然如果你想要"additional conditions",那么其实写成$unwind and $match是最高效的:

db.parent.aggregate([
  { "$lookup": {
    "from": "related",
    "localField": "b",
    "foreignField": "b",
    "as": "results"
  }},
  { "$unwind": "$results" },
  { "$match": { "results.a": 1  } }
])

这是因为 $lookup are actually "hoisted" into the $lookup 操作本身之后的以下阶段的聚合管道选项。在 "explain" 输出中显示:

    {
            "$lookup" : {
                    "from" : "related",
                    "as" : "results",
                    "localField" : "b",
                    "foreignField" : "b",
                    "unwinding" : {
                            "preserveNullAndEmptyArrays" : false
                    },
                    "matching" : {
                            "a" : {
                                    "$eq" : 1
                            }
                    }
            }
    }

这表明 "unwinding" 和 "matching" 的选项实际上已在 $lookup 中应用。到目前为止,您还不能直接编写它,但是管道组合应用了这种行为。

这实际上是为了处理 BSON 限制未被打破的问题,因为创建的数组的条目超过 16MB 上限。

简而言之,在大多数情况下,您通常需要现有行为而不需要新选项。然而