将$ lookup结果合并到现有数组 [英] Merge $lookup result to existing array

查看:356
本文介绍了将$ lookup结果合并到现有数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是mongo的新手,需要您的帮助.

I'm new to mongo and I need your help.

我收藏了 studijneProgramy .这是示例文档:

I have collection studijneProgramy. This is sample document:

{
    "_id" : "dGFY",
    "garranti" : [
        {
            "typ" : {
                "sk" : "garant",
                "en" : "Chairman of study board"
            },
            "id" : "1025769"
        },
        {
            "typ" : {
                "sk" : "predseda odborovej komisie",
                "en" : "Chairman of study board"
            },
            "id" : "1025769"
        }
    ]
}

下一步,我收集了 osoby .
示例文件:

Next I have collection osoby.
Example document:

{
    "_id" : "1025769",
    "plneMeno" : "prof. RNDr. Peter Moczo, DrSc.",
    "priezvisko" : "Moczo",
    "meno" : "Peter",
    "jeGarantProgramu" : "dGFY/x"
}

我需要的是将 osoby 中的文档添加到数组 garranti (其中studijneProgramy.garanti.id == osoby._id)中的相应文档中. 所以这是我想要的结果:

What I need is to add documets from osoby to corresponding document in array garranti (where studijneProgramy.garanti.id == osoby._id). So this is my desired result:

{
    "_id" : "dGFY",
    "garranti" : [
        {
            "typ" : {
                "sk" : "garant",
                "en" : "Chairman of study board"
            },
            "id" : "1025769"
            "garant":{
                "_id" : "1025769",
                "plneMeno" : "prof. RNDr. Peter Moczo, DrSc.",
                "priezvisko" : "Moczo",
                "meno" : "Peter",
                "jeGarantProgramu" : "dGFY/x"
            }
        },
        {
            "typ" : {
                "sk" : "predseda odborovej komisie",
                "en" : "Chairman of study board"
            },
            "id" : "1025769"
            "garant":{
                "_id" : "1025769",
                "plneMeno" : "prof. RNDr. Peter Moczo, DrSc.",
                "priezvisko" : "Moczo",
                "meno" : "Peter",
                "jeGarantProgramu" : "dGFY/x"
            }
        }
    ]
}

我尝试了这种汇总,但是它替换了 garranti 的内容.

I tried this aggregation but it replaced content of garranti.

db.studijneProgramy.aggregate([
{
    $lookup:
    {
        from:"osoby", 
        localField:"garranti.id",
        foreignField:"_id", 
        as:"garranti.garant"
    }
 }
]
).pretty()

任何帮助将不胜感激!

推荐答案

MongoDB $lookup 不会使用"lookup"集合中的匹配项来更新"现有数组中的元素.它将输出与给定条件匹配的数组",即与您所拥有的值的现有数组"或奇异值匹配的结果.

MongoDB $lookup will not "update" elements in an existing array with matches from the "lookup" collection. It will only output an "array" of the matches to the criteria given, be that matched against an "existing array" of values as you have or a singular value.

为了使条目与服务器"结婚" $lookup 操作,您必须继续使用以下选项之一才能返回所需的表单.

In order to "marry up" the entries with a "server" $lookup operation you have to proceed instead with one of the following options in order to return in the form you want.

最简单的形式是简单地更改文档的结构,以使源中的每个数组成员首先是它的自己的文档,然后再实际尝试关联"相关信息:

The simplest form is to simply change the structure of the documents so that each array member from the source is it's own document first, before you actually attempt to "marry up" the correlated information:

db.studijneProgramy.aggregate([
  { "$unwind": "$garranti" },
  { "$lookup": {
    "from": "osoby",
    "as": "garranti.garrant",
    "localField": "garranti.id",
    "foreignField": "_id"
  }},
  { "$unwind": "$garranti.garrant" },
  { "$group": {
    "_id": "$_id",
    "garranti": { "$push": "$garranti" }
  }}
])

由于原始数组材料现在是单个文档,因此每个数组仅从联接的集合中接收匹配项的数组".这将再次 $unwind ,最后使用

Since the original array material are now singular documents, then each one only receives the "array" of matches from the joined collection. This would $unwind again and finally use $group in order to $push to the final array form with "joined" entries.

在支持它的版本中,有些幻想是使用 $indexOfArray $arrayElemAt 以便匹配",将

A bit fancier in versions that support it are to use the functions of $indexOfArray and $arrayElemAt in order to "match up" the output array of $lookup to the existing array entries in the document:

db.studijneProgramy.aggregate([
  { "$lookup": {
    "from": "osoby",
    "as": "related",
    "localField": "garranti.id",
    "foreignField": "_id"
  }},
  { "$project": {
    "garranti": {
      "$map": {
        "input": "$garranti",
        "in": {
          "typ": "$$this.typ",
          "id": "$$this.id",
          "garrant": {
            "$arrayElemAt": [
              "$related",
              { "$indexOfArray": [ "$related._id", "$$this.id" ] }
            ]
          }
        }
      }
    }
  }}
])

因此,查找返回匹配数组"(related),然后您查找"这些匹配项,然后通过 $project 阶段或类似的顺序重塑文档结果,因为您无法定位" 如前所述$lookup 输出.

So the lookup returns the "array of matches" ( related ) and you "lookup" the matching entries of these and transpose them into the original document array via $map. Of course this requires an additional $project stage or similar in order to reshape the document result since you cannot "target" each element of the existing array in $lookup output as mentioned earlier.

这实际上是某些服务器(例如猫鼬")为在客户端上进行联合仿真"所做的工作在服务器"上的直接关联.实际上,外来"条目被映射"到现有阵列上.

This is actually the direct correlation on the "server" of what some libraries such as "mongoose" do for "join emulation on the client". Effectively the "foreign" entries are "mapped" onto the existing array.

使用子管道"处理 $lookup 而不是在随后的聚合阶段进行处理:

A bit fancier and long-winded is another alternative using "sub-pipeline" processing of an Uncorrelated subquery available from MongoDB 3.6 an upwards. Here we basically do the manipulation in the "sub-pipeline" of $lookup instead of processing in subsequent aggregation stages:

db.studijneProgramy.aggregate([
  { "$lookup": {
    "from": "osoby",
    "as": "garranti",
    "let": { "garranti": "$garranti" },
    "pipeline": [
      { "$match": {
        "$expr": { "$in": [ "$_id", "$$garranti.id" ] } 
      }},
      { "$addFields": {
        "docs": {
          "$filter": {
            "input": "$$garranti",
            "cond": {
              "$eq": [ "$$this.id", "$_id" ]
            }
          }
        }
      }},
      { "$unwind": "$docs" },
      { "$replaceRoot": {
        "newRoot": {
          "$mergeObjects": [
            "$docs",
            { "garrant": {
              "$arrayToObject": {
                "$filter": { 
                  "input": { "$objectToArray": "$$ROOT" },
                  "cond": { "$ne": [ "$$this.k", "docs"] }
                }
              }
            }}
          ]
        }
      }}
    ]
  }}
])

这种操作使操作顺其自然",并将源文档"中的匹配数组元素"有效地放置到每个匹配的外部元素数组中.

This sort of turns the operation "on it's head" and effectively places the "matching array elements" from the "source document" into each matched foreign element as an array.

然后,该处理有效地对过滤出的内容使用 $unwind 源列表,然后合并外部集合中的内容,因此现在看起来 $lookup 输出数组"实际上是本地数组"中的数据,现在本地数组"已与外来内容"合并.

The processing then effectively uses $unwind on the filtered source list and then merges the content from the foreign collection so it now appears that the $lookup "output array" is actually the data from the "local array" now "merged" with the "foreign content".

真的,这只是对同一个 $map 上面的过程,但是在之前进行条目的关联",结果与原始父文档合并,从而覆盖了原始数组属性.

Really it's just a fancier invocation of the same $map process above, but doing the "correlating" of entries before the results are merged with the original parent document overwriting the original array property.

我认为某个地方可以使用JIRA,但是我感觉在所有此类报告中都标有按设计工作" ,因此不太可能对其进行更改目前确实如此.

There is I think a JIRA around for this somewhere, but I sort of have the feeling that "works as designed" is marked on all such reports, so it is unlikely to change from what it presently does.

因此,您对"join"的误解将自动"与数组项合并".不会.

So the misconception you had was the "join" would "merge" with the array entries "automatically". It does not.

如果您想实际合并数组输出",那么上面的方法就是服务器"方法.

If if you want to actually "merge array output", then the approaches above are the "server" approach to do so.

这篇关于将$ lookup结果合并到现有数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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