通过引用父文档中的多个值来使用 $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" 数据相反,其中 localField
和 foreignField
可以应用于两个集合之间的 "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
})
我可以在这里使用 pipeline
和 let
语句来测试另一个集合的项目的逻辑条件,如下所示:
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 上限。
简而言之,在大多数情况下,您通常需要现有行为而不需要新选项。然而
我正在尝试 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" 数据相反,其中 localField
和 foreignField
可以应用于两个集合之间的 "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
})
我可以在这里使用 pipeline
和 let
语句来测试另一个集合的项目的逻辑条件,如下所示:
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 上限。
简而言之,在大多数情况下,您通常需要现有行为而不需要新选项。然而