聚合$ lookup不返回元素原始数组顺序 [英] Aggregate $lookup does not return elements original array order

查看:124
本文介绍了聚合$ lookup不返回元素原始数组顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

查询返回元素在其集合中的放置顺序,而忽略初始数组的顺序.这会影响我们系统的功能.是否有其他命令可以将其正确排列?有任何解决方法吗?

The query returns the order in which elements are placed in their collection, ignoring the order of the initial array. This affects the function of our system. Is there any extra command to put it in the correct order? Is there any workaround available?

以下是一个简单的示例:

Here follows a simple example:

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可以用来按照原始数组顺序返回它吗?

Are there any extra command ex. $sort that could be used to return it respecting the original arrays order?

推荐答案

这是中发生的事情是MongoDB internall 转换 $lookup 到新的 expressive 格式. mongodb.com/manual/reference/operator/query/expr/"rel =" noreferrer> $expr的内部机制实际上也是相同的.

This is "by design" of the $lookup implementation. What actually happens "under the hood" is MongoDB internall converts the arguments in the $lookup to the new expressive format using $expr and $in. Even in versions prior to when this expressive form was implemented, the internal mechanics for an "array of values" was really much the same.

这里的解决方案是维护原始数组的副本,以作为对"joined" 项目进行重新排序的参考:

The solution here is to maintain a copy of the original array as a reference for reordering the "joined" items:

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" }
  }}
])

两个变体产生相同的输出:

Both variants produce the same output:

{
        "_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值在"$Classes.ID"的原始源数组中找到它的"index" 位置.不同的 $lookup 语法变体在访问方式上有不同的方法此副本以及您的基本构造方式.

The general concept being to use $indexOfArray in comparison with the _id value from the "joined" content to find it's "index" position in the original source array from "$Classes.ID". The different $lookup syntax variants have different approaches to how you access this copy and how you basically reconstruct.

$sort 当然可以设置实际的顺序文档,可以在表达处理形式的管道处理中,也可以通过 $unwind 的地方,您将

The $sort of course sets the order of actual documents, either being inside the pipeline processing for the expressive form, or via the exposed documents of $unwind. Where you used $unwind you would then $group back to the original document form.

注意: $indexOfArray

NOTE: The usage examples here depend on MongoDB 3.4 for the $indexOfArray at least and the $$REMOVE aligns with MongoDB 3.6 as would the expressive $lookup.

还有其他方法可以对先前版本的阵列进行重新排序,但是这些方法在 Dogo MongoDB的$ in子句中有更详细的说明.保证订单.实际上,目前作为生产MongoDB版本运行的最低要求是3.4版本.

There are other approaches to re-ordering the array for prior releases, but these are demonstrated in more detail on Does MongoDB's $in clause guarantee order. Realistically the bare minimum you should presently be running as a production MongoDB version is the 3.4 release.

请参见 MongoDB Server 下的 支持政策 . strong>,以获取受支持版本和结束日期的完整详细信息.

See Support Policy under MongoDB Server for the full details of supported releases and end dates.

这篇关于聚合$ lookup不返回元素原始数组顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆