查询返回元素在其集合中的放置顺序,而忽略初始数组的顺序。这会影响我们系统的功能。是否有其他命令可以将其正确排列?有任何解决方法吗?
以下是一个简单的示例:
Collection1文档
{
"_id":ObjectId("5c781752176c512f180048e3"),
"Name":"Pedro",
"Classes":[
{"ID": ObjectId("5c7af2b2f6f6e47c9060d7ce") },
{"ID": ObjectId("5c7af2bcf6f6e47c9060d7cf") },
{"ID": ObjectId("5c7af2aaf6f6e47c9060d7cd") }
]
}
Collection2文档
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
},
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
}
查询:
aggregate(
pipeline = '[
{"$match": {"_id": {"$oid": "5c781752176c512f180048e3"}}},
{"$lookup": {"from": "collection2", "localField": "Classes.ID", "foreignField": "_id", "as": "Collection2_doc"}}
]'
)
返回:
结果的顺序:
[
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
},
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
}
]
预期顺序(第一个文档排列顺序):
[
{
"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
"variable1":"B"
},
{
"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
"variable1":"C"
},
{
"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
"variable1":"A"
}
]
例如,是否还有其他命令。 $sort
是否可以按照原始数组顺序返回它?
答案 0 :(得分:2)
这是$lookup
实现的“设计使然”。实际上 在“幕后” 中发生的事情是MongoDB internall 将$lookup
中的参数转换为新的 expressive < / em>格式,使用$expr
和$in
。即使在实现这种 expressive 形式之前的版本中,“值数组” 的内部机制实际上也是相同的。
这里的解决方案是维护原始数组的副本,以作为对“ joined” 项重新排序的参考:
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"
}}
])
或通过旧式$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" }
}}
])
两个变体产生相同的输出:
{
"_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"
}
]
}
一般概念是将$indexOfArray
与“ joined” 内容中的_id
值进行比较,以找到其“ index” "$Classes.ID"
中原始源数组中的位置。不同的$lookup
语法变体对于访问此副本的方式和基本重构的方式具有不同的方法。
$sort
当然可以设置实际文档的顺序,或者是在流水线处理内以表达形式,或者是通过$unwind
的公开文档。然后,在使用$unwind
的地方,$group
返回原始文档表单。
注意:此处的用法示例至少取决于
$indexOfArray
的MongoDB 3.4,而$$REMOVE
与MongoDB 3.6一样,与富有表现力的$lookup
。还有其他方法可以对先前版本的数组进行重新排序,但是这些方法在Does MongoDB's $in clause guarantee order中有更详细的说明。实际上,当前作为生产MongoDB版本运行的最低要求是3.4版本。
有关受支持的发行版和结束日期的详细信息,请参见 MongoDB Server 下的Support Policy。