Luc*_*elo 10 mongodb mongodb-query aggregation-framework
查询返回元素在其集合中的放置顺序,忽略初始数组的顺序。这会影响我们系统的功能。是否有任何额外的命令可以将其按正确的顺序排列?有没有可用的解决方法?
下面是一个简单的例子:
Collection1 文档
{
"_id":ObjectId("5c781752176c512f180048e3"),
"Name":"Pedro",
"Classes":[
{"ID": ObjectId("5c7af2b2f6f6e47c9060d7ce") },
{"ID": ObjectId("5c7af2bcf6f6e47c9060d7cf") },
{"ID": ObjectId("5c7af2aaf6f6e47c9060d7cd") }
]
}
Run Code Online (Sandbox Code Playgroud)
Collection2 文件
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
},
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
}
Run Code Online (Sandbox Code Playgroud)
查询:
aggregate(
pipeline = '[
{"$match": {"_id": {"$oid": "5c781752176c512f180048e3"}}},
{"$lookup": {"from": "collection2", "localField": "Classes.ID", "foreignField": "_id", "as": "Collection2_doc"}}
]'
)
Run Code Online (Sandbox Code Playgroud)
返回:
结果顺序:
[
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
},
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
}
]
Run Code Online (Sandbox Code Playgroud)
预期顺序(第一个文档数组顺序):
[
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
},
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
}
]
Run Code Online (Sandbox Code Playgroud)
是否有任何额外的命令 ex. $sort
可以用来返回它尊重原始数组顺序?
Nei*_*unn 22
这是实现的“设计” $lookup
。什么实际发生的“引擎盖下”是MongoDB的internall转换中的参数$lookup
,以新的表现力使用的格式$expr
和$in
。即使在实现这种表达形式之前的版本中,“值数组”的内部机制也非常相似。
这里的解决方案是保留原始数组的副本作为重新排序“连接”项的参考:
collection.aggregate([
{"$match": {"_id": ObjectId("5c781752176c512f180048e3") }},
{"$lookup": {
"from": "collection2",
"let": { "classIds": "$Classes.ID" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ "$_id", "$$classIds" ] }
}},
{ "$addFields": {
"sort": {
"$indexOfArray": [ "$$classIds", "$_id" ]
}
}},
{ "$sort": { "sort": 1 } },
{ "$addFields": { "sort": "$$REMOVE" }}
],
"as": "results"
}}
])
Run Code Online (Sandbox Code Playgroud)
或者按照传统$lookup
用法:
collection.aggregate([
{"$match": {"_id": ObjectId("5c781752176c512f180048e3") }},
{"$lookup": {
"from": "collection2",
"localField": "Classes.ID",
"foreignField": "_id",
"as": "results"
}},
{ "$unwind": "$results" },
{ "$addFields": {
"sort": {
"$indexOfArray": [ "$Classes.ID", "$results._id" ]
}
}},
{ "$sort": { "_id": 1, "sort": 1 } },
{ "$group": {
"_id": "$_id",
"Name": { "$first": "$Name" },
"Classes": { "$first": "$Classes" },
"results": { "$push": "$results" }
}}
])
Run Code Online (Sandbox Code Playgroud)
两种变体产生相同的输出:
{
"_id" : ObjectId("5c781752176c512f180048e3"),
"Name" : "Pedro",
"Classes" : [
{
"ID" : ObjectId("5c7af2b2f6f6e47c9060d7ce")
},
{
"ID" : ObjectId("5c7af2bcf6f6e47c9060d7cf")
},
{
"ID" : ObjectId("5c7af2aaf6f6e47c9060d7cd")
}
],
"results" : [
{
"_id" : ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1" : "B"
},
{
"_id" : ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1" : "C"
},
{
"_id" : ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1" : "A"
}
]
}
Run Code Online (Sandbox Code Playgroud)
一般概念是$indexOfArray
与_id
来自“连接”内容的值进行比较,以找到它在原始源数组中的“索引”位置"$Classes.ID"
。不同的$lookup
语法变体对于如何访问此副本以及如何基本重建有不同的方法。
在$sort
任一被当然设置实际文件的顺序,所述流水线处理内部的表现形式,或经由的暴露文件$unwind
。您使用的地方$unwind
然后将$group
返回到原始文档形式。
注意:此处的使用示例
$indexOfArray
至少依赖于 MongoDB 3.4,并且$$REMOVE
与 MongoDB 3.6 一致,表达方式也一样$lookup
。还有其他方法可以为以前的版本重新排序数组,但这些方法在MongoDB 的 $in 子句保证顺序中有更详细的演示。实际上,您目前应该作为生产 MongoDB 版本运行的最低限度是 3.4 版本。
有关受支持版本和结束日期的完整详细信息,请参阅MongoDB 服务器下的支持政策。
归档时间: |
|
查看次数: |
2509 次 |
最近记录: |