我需要使用aggregate $ lookup加入两个集合中的两个以上的字段。有可能加入吗?如果有可能请告诉我。这里我有两个系列:
例如: "人"收藏领域"城市,州,国家" in" country"收集字段" city_id,state_id,country_id",我想在以下集合中加入这三个字段。
"人"
{
"_id" : 1,
"email" : "admin@gmail.com",
"userId" : "AD",
"userName" : "admin",
"city" : 1,
"state" : 1,
"country" : 1
}
"国家"
{
"country_id" : 1,
"userId" : "AD",
"phone" : "0000000000",
"stateinfo":[{
"state_id" : 1,
"state_name" : "State1"
},{
"state_id" : 2,
"state_name" : "State2"
}
],
"cityinfo":[{
"city_id" : 1,
"city_name" : "city1"
},{
"city_id" : 2,
"city_name" : "city2"
}
]
}
答案 0 :(得分:2)
这可能比你想象的要简单得多,考虑到当然所有的"三"字段包含在一个"country"
文档中。因此,只需按"country_id"
执行$lookup
,然后使用已审核的内容填充其他字段。
var pipeline = [
{ "$lookup": {
"from": "country",
"localField": "country",
"foreignField": "country_id",
"as": "country"
}},
{ "$project": {
"email": 1,
"userId": 1,
"userName": 1,
"country": {
"$arrayElemAt": [
{ "$filter": {
"input": {
"$map": {
"input": "$country",
"as": "country",
"in": {
"country_id": "$$country.country_id",
"userId": "$$country.userId",
"phone": "$$country.phone",
"stateInfo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$$country.stateInfo",
"as": "state",
"cond": { "$eq": [ "$$state.state_id", "$state" ] }
}},
0
]
},
"cityinfo": {
"$arrayElemAt": [
{ "$filter": {
"input": "$$country.cityinfo",
"as": "city",
"cond": { "$eq": [ "$$city.city_id", "$city" ] }
}},
0
]
}
}
}
},
"as": "country",
"cond": { "$eq": [ "$$country.userId", "$userId" ] }
}},
0
]
}
}}
]
db.people.aggregate(pipeline)
这应该会给你一个结果:
{
"_id" : 1,
"email" : "admin@gmail.com",
"userId" : "AD",
"userName" : "admin",
"country" : {
"country_id" : 1,
"userId" : "AD",
"phone" : "0000000000",
"stateinfo": {
"state_id" : 1,
"state_name" : "State1"
},
"cityinfo": {
"city_id" : 1,
"city_name" : "city1"
}
}
因此,一旦数组与$lookup
匹配,所有内容都归结为使用$filter
进行匹配,$arrayElemAt
从每个过滤后的数组中获取第一个匹配。
由于外部数组具有"内部"数组,你想使用$map
作为"外部"来源并将$filter
应用于每个内部"内部"阵列。
你可以通过$let
获得更多的幻想来减少"减少"数组内容一直到返回的子文档,然后直接引用一个偶数"更平坦的"响应,但"匹配"的一般概念数组元素与上面的相同。
对于PHP结构转换:
$pipeline = array(
array(
'$lookup' => array(
'from' => 'country',
'localField' => 'country'
'foreignField' => 'country_id',
'as' => 'country'
)
)
array(
'$project' => array(
'email' => 1,
'userId' => 1,
'userName' => 1,
'country' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => array(
'$map' => array(
'input' => '$country',
'as' => 'country',
'in' => {
'country_id' => '$$country.country_id',
'userId' => '$$country.userId',
'phone' => '$$country.phone',
'stateInfo' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => '$$country.stateInfo',
'as' => 'state',
'cond' => array( '$eq' => array( '$$state.state_id', '$state' ) )
)
),
0
)
),
'cityinfo' => array(
'$arrayElemAt' => array(
array(
'$filter' => array(
'input' => '$$country.cityinfo',
'as' => 'city',
'cond' => array( '$eq' => array( '$$city.city_id', '$city' ) )
)
),
0
)
)
}
)
),
'as' => 'country',
'cond' => array( '$eq' => array( '$$country.userId', '$userId' ) )
)
),
0
)
)
)
)
);
$people->aggregate($pipeline);
当您通过转储管道结构从JSON示例工作时,通常可以检查PHP是否与JSON结构匹配:
echo json_encode($pipeline, JSON_PRETTY_PRINT)
这样你就不会出错。
作为另一个最后的注释,$lookup
完成之后的过程非常复杂"即使非常有效率。所以我建议,除非有必要进一步采用这种聚合管道,实际上"聚合"什么东西,那么你可能会更好地做到这一点"过滤"在客户端代码而不是在服务器上执行。
执行相同操作的客户端代码远远不够"钝"而不是你需要告诉聚合管道做什么。所以除非这个"真的"通过减少匹配的数组来节省大量的带宽使用,或者实际上只要你能查找"通过做另一个查询,然后坚持在代码中执行它和/或进行单独的查询。