select tb1.*,tb3 from tb1,tb2,tb3
where tb1.id=tb2.profile_id and tb2.field='<text>'
and tb3.user_id = tb2.id and tb3.status =0
实际上我将sql转换为mongo
sql,如下所示
mongo
sql
db.getCollection('tb1').aggregate
([
{ $lookup:
{ from: 'tb2',
localField: 'id',
foreignField: 'profile_id',
as: 'tb2detail'
}
},
{ $lookup:
{ from: 'tb3',
localField: 'tb2.id',
foreignField: 'user_id',
as: 'tb3details'
}
},
{ $match:
{ 'status':
{ '$ne': 'closed'
},
'tb2.profile_type': 'agent',
'tb3.status': 0
}
}
])
但没有达到预期的结果..
任何帮助将不胜感激..
答案 0 :(得分:6)
你在这里缺少的是$lookup
产生一个&#34;数组&#34;在as
中由db.getCollection.('tb1').aggregate([
// Filter conditions from the source collection
{ "$match": { "status": { "$ne": "closed" } }},
// Do the first join
{ "$lookup": {
"from": "tb2",
"localField": "id",
"foreignField": "profileId",
"as": "tb2"
}},
// $unwind the array to denormalize
{ "$unwind": "$tb2" },
// Then match on the condtion for tb2
{ "$match": { "tb2.profile_type": "agent" } },
// join the second additional collection
{ "$lookup": {
"from": "tb3",
"localField": "tb2.id",
"foreignField": "id",
"as": "tb3"
}},
// $unwind again to de-normalize
{ "$unwind": "$tb3" },
// Now filter the condition on tb3
{ "$match": { "tb3.status": 0 } },
// Project only wanted fields. In this case, exclude "tb2"
{ "$project": { "tb2": 0 } }
])
指定的输出字段中。这是MongoDB&#34;关系&#34;的一般概念,即&#34;关系&#34;文档之间表示为&#34;子属性&#34;那是&#34;在&#34;内文档本身,可以是单数或&#34;数组&#34;很多人。
由于MongoDB是&#34;无模式&#34;,$lookup
的一般假设是你的意思是&#34;很多&#34;结果因此总是&#34;数组。所以寻找与SQL相同的结果&#34;然后你需要在$unwind
之后$lookup
那个数组。是否&#34;一个&#34;或者&#34;很多&#34;没有任何意义,因为它仍然总是&#34;一个数组:
ps -ef | grep mongod | grep -v grep | awk '{ print $1 }'
在这里,您需要注意翻译中缺少的其他内容:
聚合管道更具表现力和表达能力。比SQL。事实上,它们最好被视为&#34;一系列步骤&#34; 应用于数据源以整理和转换数据。对此最好的模拟是&#34;管道&#34;命令行指令,例如:
|
&#34;管道&#34; grep
可被视为&#34;管道阶段&#34;在MongoDB聚合&#34;管道&#34;。
因此我们想要$match
来过滤来自&#34;来源&#34;收集作为我们的第一次操作这通常是一种很好的做法,因为它可以从其他条件中删除任何不符合要求条件的文档。就像在我们的&#34;命令行管道中发生的那样#34;例如,我们采取&#34;输入&#34;然后&#34;管#34;到"from"
到&#34;删除&#34;或&#34;过滤&#34;。
你在这里做的下一件事是&#34;加入&#34;通过$lookup
。结果是&#34;数组&#34;来自"as"
集合参数的项目与提供的字段匹配,以输出"tb2"
&#34;字段路径&#34;作为&#34;阵列&#34;。
这里选择的命名很重要,因为现在&#34;文件&#34;来自源集合考虑来自&#34; join&#34;的所有项目。现在存在于那条特定的道路上。为了方便起见,我使用相同的&#34;集合&#34;命名为&#34;加入&#34;对于新的&#34;路径&#34;。
从第一次开始#34;加入&#34;输出到$lookup
,这将保存该集合的所有结果。关于MongoDB如何实际处理查询,以下$unwind
和$match
序列还有一点需要注意。
因为它看起来像&#34;有&#34;三&#34;管道阶段,{ "explain": true }
然后$unwind
然后$match
。但在&#34;事实&#34; MongoDB确实做了其他事情,这在添加到.aggregate()
命令的 {
"$lookup" : {
"from" : "tb2",
"as" : "tb2",
"localField" : "id",
"foreignField" : "profileId",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"profile_type" : {
"$eq" : "agent"
}
}
}
},
{
"$lookup" : {
"from" : "tb3",
"as" : "tb3",
"localField" : "tb2.id",
"foreignField" : "id",
"unwinding" : {
"preserveNullAndEmptyArrays" : false
},
"matching" : {
"status" : {
"$eq" : 0.0
}
}
}
},
输出中得到了证明:
unwinding
除了&#34;序列&#34;的第一点之外应用于需要将$match
语句放在需要的位置并执行“最好的”#34;这实际上变得非常重要&#34;与&#34;加入&#34;的概念。这里要注意的是,$lookup
然后$unwind
然后$match
的序列实际上被MongoDB处理为$lookup
阶段,其他操作&# 34;卷起&#34;进入每个管道阶段。
这是对过滤&#34;过滤&#34;的其他方式的重要区别。 $lookup
获得的结果。因为在这种情况下,实际的&#34;查询&#34; &#34;加入&#34;的条件从$match
开始对集合进行加入&#34;之前&#34;结果将返回给父母。
这与$unwind
(被翻译为preserveNullAndEmptyArrays: false
)结合如上所示是MongoDB如何实际处理&#34;加入&#34;可能导致在源文档中生成一系列内容,导致其超过16MB BSON限制。这只会在加入的结果非常大的情况下发生,但同样的优势在于&#34;过滤器&#34;实际上是应用于目标集合&#34;之前&#34;结果返回。
这种处理最好&#34;关联&#34;与SQL JOIN的行为相同。因此,它也是获得$lookup
结果的最有效方法,除了简单的&#34; local&#34;之外还有其他条件适用于JOIN。 &#34;外国&#34;关键值。
另请注意,其他行为更改来自$lookup
执行的LEFT JOIN,其中&#34; source&#34;无论“目标”中是否存在匹配的文档,都将始终保留文档。采集。相反,$unwind
通过&#34;丢弃&#34;来自&#34;来源&#34;的任何结果它与#34; target&#34;没有任何匹配。根据{{3}}中的其他条件。
事实上,由于隐含的
{ "$group": { "_id": "$_id", "tb1_field": { "$first": "$tb1_field" }, "tb1_another": { "$first": "$tb1_another" }, "tb3": { "$push": "$tb3" } }}
被包括在内,它们甚至被预先丢弃,并且会丢弃任何地方&#34; local&#34;和&#34;外国&#34;两个集合之间的密钥甚至不匹配。对于这种特殊类型的查询,这是一件好事,因为&#34; join&#34;是为了平等#34;关于这些价值观。
如前所述,MongoDB通常会处理&#34;关系&#34;与你如何使用&#34;关系数据库&#34;有很大的不同。或者RDBMS。 &#34;关系的一般概念&#34;事实上&#34;嵌入&#34;数据,可以是单个属性,也可以是数组。
您实际上可能需要这样的输出,这也是为什么在没有$match
序列的情况下$unwind
的输出实际上是&#34;数组&#34;的原因的一部分。但是,在这种情况下使用$lookup
实际上是最有效的事情,并且保证&#34;加入&#34;数据实际上不会导致上述BSON限制超过&#34;加入&#34;。
如果你真的想要输出数组,那么在这里做的最好的事情就是使用$unwind
流水线阶段,并且可能作为多个阶段,以便&#34;规范化&#34;和&#34;撤消结果&#34; $group
"tb1"
事实上,对于此案例,您需要使用$unwind
列出"tb2"
所需的所有字段,仅使用$first
来保留&#34;第一个&#34;发生(基本上由"tb3"
和"tb3"
展开的结果重复)然后$push
&#34;详细信息&#34;从"tb1"
到#34;阵列&#34;表示与{{1}}的关系。
但是给定的聚合管道的一般形式是如何从原始SQL获得结果的精确表示,其是“非规范化的”#34;输出&#34;加入&#34;。您是否想要&#34;正常化&#34;这取决于你的结果。