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

时间:2017-06-28 03:59:42

标签: mongodb aggregation-framework lookup

我正在试用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"
            }
       }
    ])

谢谢

1 个答案:

答案 0 :(得分:1)

这里不清楚你的意思,你可能意味着将let与新的pipeline选项一起使用,但它也可能意味着一个完全不同的情况

pipeline操作通常用于"非关联"数据检索,在各种用例中都很有用。这与"相关"相反。可以将localFieldforeignField应用于"加入"的数据两个集合之间。

如上所述,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中提供的相关集合的变量进行测试的。

这允许你也使用"逻辑"过滤器,例如$redact

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

返回:

{
        "_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中引入的现有功能已经涵盖了正常的"相关的"选项:

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

与上述结果相同。

当然,如果您需要"附加条件",那么使用$unwind$match进行写作效率最高:

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

这是因为$lookup之后的以下阶段的汇总管道选项实际上是#34;悬挂"进入$lookup操作本身。在"解释"中展示输出:

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

这显示"展开"的选项和#34;匹配"实际上已在$lookup内应用。到目前为止,您不能直接编写它,但管道组合会应用此行为。

事实上,这基本上是因为创建一个条目超过16MB上限的数组而没有被破坏的BSON限制。

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