使用 $lookup 时数组会重新排序

问题描述 投票:0回答:3

我有这个聚合:

db.getCollection("users").aggregate([
  {
    "$match": {
      "_id": "5a708a38e6a4078bd49f01d5"
    }
  },
  {
    "$lookup": {
      "from": "user-locations",
      "localField": "locations",
      "as": "locations",
      "foreignField": "_id"
    }
  }
])

它运行良好,但有一件小事情我不明白并且无法修复。 在查询输出中,

locations
数组由ObjectId重新排序
,我确实需要保持数据的原始顺序。

这是

locations

 集合中的 
users
 数组的样子

'locations' : [ ObjectId("5b55e9820b720a1a7cd19633"), ObjectId("5a708a38e6a4078bd49ef13f") ],
这是聚合后的结果:

'locations' : [ { '_id' : ObjectId("5a708a38e6a4078bd49ef13f"), 'name': 'Location 2' }, { '_id' : ObjectId("5b55e9820b720a1a7cd19633"), 'name': 'Location 1' } ],
我在这里缺少什么?我真的不知道如何处理这个问题。
可以推我一下吗?

mongodb aggregation-framework lookup
3个回答
3
投票

$lookup

不保证结果文档的顺序,您可以尝试一种管理文档自然顺序的方法,

  • $unwind
    解构
    locations
    数组并添加自动
    index
    数字将从0开始,
  • $lookup
     与地点
  • $set
    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" } } } ])

游乐场


3
投票
从此

已关闭的错误报告

使用$lookup时,不保证返回文档的顺序。文档按“自然顺序”返回 - 正如它们在数据库中遇到的那样。获得保证一致顺序的唯一方法是向查询添加 $sort 阶段。

基本上任何 Mongo 查询/管道的工作方式都是按照匹配的顺序返回文档,这意味着不能保证“正确”的顺序,尤其是在涉及 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
 即可恢复结构。


0
投票
试试这个:

db.getCollection("users").aggregate([ { "$match": { "_id": "5a708a38e6a4078bd49f01d5" } }, { "$lookup": { "from": "user-locations", "localField": "locations", "foreignField": "_id", "let": { indexArray: "$locations", }, "pipeline": [ { "$addFields": { "index": { "$indexOfArray": ["$$indexArray", "$_id"] } } }, { "$sort": { "index": 1 } } ], "as": "locations", } } ])
    
© www.soinside.com 2019 - 2024. All rights reserved.