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

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

问题描述

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

下面是一个简单的例子:

Collection1 文档

<代码>{"_id":ObjectId("5c781752176c512f180048e3"),"姓名":"佩德罗",类":[{"ID": ObjectId("5c7af2b2f6f6e47c9060d7ce") },{"ID": ObjectId("5c7af2bcf6f6e47c9060d7cf") },{ID":ObjectId(5c7af2aaf6f6e47c9060d7cd")}]}

Collection2 文档

<代码>{"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),变量1":A"},{"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),变量1":B"},{"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),变量1":C"}

查询:

聚合(管道 = '[{"$match": {"_id": {"$oid": "5c781752176c512f180048e3"}}},{"$lookup": {"from": "collection2", "localField": "Classes.ID", "foreignField": "_id", "as": "Collection2_doc"}}]')

返回:

结果顺序:

<预><代码>[{"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),变量1":A"},{"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),变量1":B"},{"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),变量1":C"}]

预期顺序(第一个文档数组顺序):

<预><代码>[{"_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),变量1":B"},{"_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),变量1":C"},{"_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),变量1":A"}]

是否有任何额外的命令 ex.$sort 可用于按照原始数组顺序返回它?

解决方案

这是设计的"$lookup 实现.实际上发生的幕后"是MongoDB内部转换$lookup 到新的 expressive 格式,使用 $expr$in.即使在实现这种表达性形式之前的版本中,值数组"的内部机制也非常相似.

这里的解决方案是保留原始数组的副本作为重新排序joined"项的参考:

collection.aggregate([{"$match": {"_id": ObjectId("5c781752176c512f180048e3") }},{$查找":{来自":collection2",让":{classIds":$Classes.ID"},管道":[{$匹配":{"$expr": { "$in": [ "$_id", "$$classIds";] }}},{$addFields":{排序":{"$indexOfArray": [ "$$classIds", "$_id";]}}},{ "$sort": { "sort": 1 } },{ "$addFields": { "sort": "$$REMOVE";}}],作为":结果"}}])

或者通过传统的 $lookup 用法:

collection.aggregate([{$match":{_id":ObjectId(5c781752176c512f180048e3")}},{$查找":{来自":collection2",localField":Classes.ID",foreignField":_id",作为":结果"}},{ "$unwind": "$results";},{$addFields":{排序":{$indexOfArray": [ $Classes.ID", $results._id";]}}},{ "$sort": { "_id": 1, "sort": 1 } },{$组":{_id":$_id",姓名":{$first":$姓名"},类":{$first":$类"},结果":{$push":$results";}}}])

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

<代码>{_id": ObjectId(5c781752176c512f180048e3"),姓名":佩德罗",类": [{身份证": ObjectId(5c7af2b2f6f6e47c9060d7ce")},{身份证": ObjectId(5c7af2bcf6f6e47c9060d7cf")},{身份证": ObjectId(5c7af2aaf6f6e47c9060d7cd")}],结果": [{_id": ObjectId(5c7af2b2f6f6e47c9060d7ce"),变量1":B"},{_id": ObjectId(5c7af2bcf6f6e47c9060d7cf"),变量1":C"},{_id": ObjectId(5c7af2aaf6f6e47c9060d7cd"),变量1":A"}]}

一般概念是使用 $indexOfArrayjoined" 内容中的 _id 值进行比较,以找到它在原始源中的 index" 位置"$Classes.ID" 中的数组.不同的 $lookup 语法变体有您如何访问此副本以及您如何基本重建的不同方法.

$sortcourse 设置实际文档的顺序,要么在管道内处理用于表达形式,要么通过 $unwind.在您使用 $unwind 的地方,您会然后 $group 回到原来的文档形式.

<块引用>

注意:此处的用法示例依赖于 MongoDB 3.4 的 $indexOfArray 至少和 $$REMOVE 与 MongoDB 3.6 一致,expressive $lookup 也是如此.

还有其他方法可以为以前的版本重新排序数组,但这些方法在 MongoDB 的 $in 子句中有更详细的说明保证订单.实际上,您目前应该作为生产 MongoDB 版本运行的最低限度是 3.4 版本.

请参阅 MongoDB 服务器 下的 支持政策strong> 有关受支持版本和结束日期的完整详细信息.

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 Document

{
  "_id":ObjectId("5c781752176c512f180048e3"),
  "Name":"Pedro",
  "Classes":[
    {"ID": ObjectId("5c7af2b2f6f6e47c9060d7ce") },
    {"ID": ObjectId("5c7af2bcf6f6e47c9060d7cf") },
    {"ID": ObjectId("5c7af2aaf6f6e47c9060d7cd") }
  ]
}

Collection2 Documents

{
  "_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
  "variable1":"A"
},

{
  "_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
  "variable1":"B"
},

{
  "_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
  "variable1":"C"
}

The query:

aggregate(
  pipeline = '[
  {"$match": {"_id": {"$oid": "5c781752176c512f180048e3"}}},
  {"$lookup": {"from": "collection2", "localField": "Classes.ID", "foreignField": "_id", "as": "Collection2_doc"}}
  ]'
)

Returns:

Result's order:

[
    {
      "_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
      "variable1":"A"
    },
    {
      "_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
      "variable1":"B"
    },
    {
      "_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
      "variable1":"C"
    }
]

Expected order (first document array order):

[
    {
      "_id": ObjectId("5c7af2b2f6f6e47c9060d7ce"),
      "variable1":"B"
    },
    {
      "_id": ObjectId("5c7af2bcf6f6e47c9060d7cf"),
      "variable1":"C"
    },
    {
      "_id":ObjectId("5c7af2aaf6f6e47c9060d7cd"),
      "variable1":"A"
    }
]

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

解决方案

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.

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

Or by the legacy $lookup usage:

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

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.

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.

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.

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.

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

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

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