使用 $lookup 时数组被重新排序
Array is reordered when using $lookup
我有这个聚合:
db.getCollection("users").aggregate([
{
"$match": {
"_id": "5a708a38e6a4078bd49f01d5"
}
},
{
"$lookup": {
"from": "user-locations",
"localField": "locations",
"as": "locations",
"foreignField": "_id"
}
}
])
它运行良好,但有一件小事我不明白,我无法修复。
在查询输出中,locations
数组被 ObjectId
重新排序,我真的需要保持数据的原始顺序。
users
集合中的 locations
数组如下所示
'locations' : [
ObjectId("5b55e9820b720a1a7cd19633"),
ObjectId("5a708a38e6a4078bd49ef13f")
],
这是聚合后的结果:
'locations' : [
{
'_id' : ObjectId("5a708a38e6a4078bd49ef13f"),
'name': 'Location 2'
},
{
'_id' : ObjectId("5b55e9820b720a1a7cd19633"),
'name': 'Location 1'
}
],
我在这里错过了什么?我真的不知道如何处理这个问题。
可以推一下吗?
When using $lookup, the order of the documents returned is not guaranteed. The documents are returned in "natural order" - as they are encountered in the database. The only way to get a guaranteed consistent order is to add a $sort stage to the query.
基本上任何 Mongo query/pipeline 的工作方式是 returns 按照它们匹配的顺序记录文件,这意味着不能保证“正确”的顺序,尤其是在使用 indes 的情况下涉及。
您应该按照建议添加一个 $sort
阶段,如下所示:
db.collection.aggregate([
{
"$match": {
"_id": "5a708a38e6a4078bd49f01d5"
}
},
{
"$lookup": {
"from": "user-locations",
"let": {
"locations": "$locations"
},
"pipeline": [
{
"$match": {
"$expr": {
"$setIsSubset": [
[
"$_id"
],
"$$locations"
]
}
}
},
{
$sort: {
_id: 1 // any other sort field you want.
}
}
],
"as": "locations",
}
}
])
您还可以保留您正在使用的原始 $lookup
语法,只使用 $unwind
、$sort
和 $group
来恢复结构。
$lookup
不保证结果文档的顺序,您可以尝试一种管理文档自然顺序的方法,
$unwind
解构locations
数组并添加自动index
数字将从0开始,
$lookup
位置
$set
到 select 来自 locations
的第一个元素
$sort
按 index
字段升序排列
$group
通过 _id
并重构 locations
数组
db.users.aggregate([
{ $match: { _id: "5a708a38e6a4078bd49f01d5" } },
{
$unwind: {
path: "$locations",
includeArrayIndex: "index"
}
},
{
$lookup: {
from: "user-locations",
localField: "locations",
foreignField: "_id",
as: "locations"
}
},
{ $set: { locations: { $arrayElemAt: ["$locations", 0] } } },
{ $sort: { index: 1 } },
{
$group: {
_id: "$_id",
locations: { $push: "$locations" }
}
}
])
我有这个聚合:
db.getCollection("users").aggregate([
{
"$match": {
"_id": "5a708a38e6a4078bd49f01d5"
}
},
{
"$lookup": {
"from": "user-locations",
"localField": "locations",
"as": "locations",
"foreignField": "_id"
}
}
])
它运行良好,但有一件小事我不明白,我无法修复。
在查询输出中,locations
数组被 ObjectId
重新排序,我真的需要保持数据的原始顺序。
users
集合中的 locations
数组如下所示
'locations' : [
ObjectId("5b55e9820b720a1a7cd19633"),
ObjectId("5a708a38e6a4078bd49ef13f")
],
这是聚合后的结果:
'locations' : [
{
'_id' : ObjectId("5a708a38e6a4078bd49ef13f"),
'name': 'Location 2'
},
{
'_id' : ObjectId("5b55e9820b720a1a7cd19633"),
'name': 'Location 1'
}
],
我在这里错过了什么?我真的不知道如何处理这个问题。 可以推一下吗?
When using $lookup, the order of the documents returned is not guaranteed. The documents are returned in "natural order" - as they are encountered in the database. The only way to get a guaranteed consistent order is to add a $sort stage to the query.
基本上任何 Mongo query/pipeline 的工作方式是 returns 按照它们匹配的顺序记录文件,这意味着不能保证“正确”的顺序,尤其是在使用 indes 的情况下涉及。
您应该按照建议添加一个 $sort
阶段,如下所示:
db.collection.aggregate([
{
"$match": {
"_id": "5a708a38e6a4078bd49f01d5"
}
},
{
"$lookup": {
"from": "user-locations",
"let": {
"locations": "$locations"
},
"pipeline": [
{
"$match": {
"$expr": {
"$setIsSubset": [
[
"$_id"
],
"$$locations"
]
}
}
},
{
$sort: {
_id: 1 // any other sort field you want.
}
}
],
"as": "locations",
}
}
])
您还可以保留您正在使用的原始 $lookup
语法,只使用 $unwind
、$sort
和 $group
来恢复结构。
$lookup
不保证结果文档的顺序,您可以尝试一种管理文档自然顺序的方法,
$unwind
解构locations
数组并添加自动index
数字将从0开始,$lookup
位置$set
到 select 来自locations
的第一个元素
$sort
按index
字段升序排列$group
通过_id
并重构locations
数组
db.users.aggregate([
{ $match: { _id: "5a708a38e6a4078bd49f01d5" } },
{
$unwind: {
path: "$locations",
includeArrayIndex: "index"
}
},
{
$lookup: {
from: "user-locations",
localField: "locations",
foreignField: "_id",
as: "locations"
}
},
{ $set: { locations: { $arrayElemAt: ["$locations", 0] } } },
{ $sort: { index: 1 } },
{
$group: {
_id: "$_id",
locations: { $push: "$locations" }
}
}
])