使用MongoDB更新嵌套数组 [英] Updating a Nested Array with MongoDB

查看:168
本文介绍了使用MongoDB更新嵌套数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试更新嵌套数组中的值但无法使其工作。

I am trying to update a value in the nested array but can't get it to work.

我的对象是这样的

 {
    "_id": {
        "$oid": "1"
    },
    "array1": [
        {
            "_id": "12",
            "array2": [
                  {
                      "_id": "123",
                      "answeredBy": [],
                  },
                  {
                      "_id": "124",
                      "answeredBy": [],
                  }
             ],
         }
     ]
 }

我需要将值推送到answersBy数组。

I need to push a value to "answeredBy" array.

在下面的示例中,我尝试将success字符串推送到123 _id对象的answersBy数组但是它不起作用。

In the below example, I tried pushing "success" string to the "answeredBy" array of the "123 _id" object but it does not work.

callback = function(err,value){
     if(err){
         res.send(err);
     }else{
         res.send(value);
     }
};
conditions = {
    "_id": 1,
    "array1._id": 12,
    "array2._id": 123
  };
updates = {
   $push: {
     "array2.$.answeredBy": "success"
   }
};
options = {
  upsert: true
};
Model.update(conditions, updates, options, callback);

我发现这是链接,但它的答案只说我应该使用类似对象的结构而不是数组。这不适用于我的情况。我真的需要将我的对象嵌套在数组中

I found this link, but its answer only says I should use object like structure instead of array's. This cannot be applied in my situation. I really need my object to be nested in arrays

如果你能在这里帮助我会很棒。我花了好几个小时来解决这个问题。

It would be great if you can help me out here. I've been spending hours to figure this out.

提前谢谢你!

推荐答案

一般范围和解释



你在这里做的事情有些不对劲。首先是您的查询条件。你指的是你应该不需要的几个 _id 值,其中至少有一个不在顶层。

General Scope and Explanation

There are a few things wrong with what you are doing here. Firstly your query conditions. You are referring to several _id values where you should not need to, and at least one of which is not on the top level.

为了进入嵌套值并且还假设 _id 值是唯一的并且不会出现在任何其他文档中,您的查询表单应该是像这样:

In order to get into a "nested" value and also presuming that _id value is unique and would not appear in any other document, you query form should be like this:

Model.update(
    { "array1.array2._id": "123" },
    { "$push": { "array1.0.array2.$.answeredBy": "success" } },
    function(err,numAffected) {
       // something with the result in here
    }
);

现在这实际上会有效,但实际上它只是一个侥幸,因为它非常好为什么它不适合你。

Now that would actually work, but really it is only a fluke that it does as there are very good reasons why it should not work for you.

重要的读物是在位置 $ 运算符,以嵌套数组为主题。这就是:

The important reading is in the official documentation for the positional $ operator under the subject of "Nested Arrays". What this says is:


位置$运算符不能用于遍历多个数组的查询,例如遍历数组的查询在其他数组中,因为$占位符的替换是单个值

The positional $ operator cannot be used for queries which traverse more than one array, such as queries that traverse arrays nested within other arrays, because the replacement for the $ placeholder is a single value

具体来说,这意味着要匹配的元素和在位置占位符中返回的是第一个匹配数组中的索引值。这意味着在你的情况下顶级数组上的匹配索引。

Specifically what that means is the element that will be matched and returned in the positional placeholder is the value of the index from the first matching array. This means in your case the matching index on the "top" level array.

因此,如果你看一下如图所示的查询符号,我们就硬编码顶级数组中的第一个(或0索引)位置,恰好array2中的匹配元素也是零索引条目。

So if you look at the query notation as shown, we have "hardcoded" the first ( or 0 index ) position in the top level array, and it just so happens that the matching element within "array2" is also the zero index entry.

为了证明这一点,您可以将匹配的 _id 值更改为124,结果将 $ push 使用 _id 123进入元素的新条目,因为它们都在array1的零索引条目中,这是返回到占位符的值。

To demonstrate this you can change the matching _id value to "124" and the result will $push an new entry onto the element with _id "123" as they are both in the zero index entry of "array1" and that is the value returned to the placeholder.

这是嵌套数组的一般问题。你可以删除其中一个级别,你仍然可以 $ push 到top数组中的正确元素,但仍有多个级别。

So that is the general problem with nesting arrays. You could remove one of the levels and you would still be able to $push to the correct element in your "top" array, but there would still be multiple levels.

尝试避免嵌套数组,因为你会遇到更新问题,如图所示。

Try to avoid nesting arrays as you will run into update problems as is shown.

一般情况是压扁你认为是水平的东西,实际上在最终细节项目上制作论文属性。例如,问题中结构的扁平形式应该是这样的:

The general case is to "flatten" the things you "think" are "levels" and actually make theses "attributes" on the final detail items. For example, the "flattened" form of the structure in the question should be something like:

 {
   "answers": [
     { "by": "success", "type2": "123", "type1": "12" }
   ]
 }

或者甚至在接受内部数组时 $ push ,且从未更新:

Or even when accepting the inner array is $push only, and never updated:

 {
   "array": [
     { "type1": "12", "type2": "123", "answeredBy": ["success"] },
     { "type1": "12", "type2": "124", "answeredBy": [] }
   ]
 }

这两者都适用于位置 $ 运算符

Which both lend themselves to atomic updates within the scope of the positional $ operator

从MongoDB 3.6开始,有一些新功能可用于嵌套数组。这使用位置过滤 $ [< identifier> ;] 语法以匹配特定元素并通过更新语句中的 arrayFilters 应用不同的条件:

From MongoDB 3.6 there are new features available to work with nested arrays. This uses the positional filtered $[<identifier>] syntax in order to match the specific elements and apply different conditions through arrayFilters in the update statement:

Model.update(
  {
    "_id": 1,
    "array1": {
      "$elemMatch": {
        "_id": "12","array2._id": "123"
      }
    }
  },
  {
    "$push": { "array1.$[outer].array2.$[inner].answeredBy": "success" }
  },
  {
    "arrayFilters": [{ "outer._id": "12" },{ "inner._id": "123" }] 
  }
)

传递给arrayFilters ://docs.mongodb.com/manual/reference/method/db.collection.update/\"rel =noreferrer> .update() 或甚至
.updateOne() .updateMany() .findOneAndUpdate() .bulkWrite( ) 方法指定与update语句中给出的标识符匹配的条件。任何与给定条件匹配的元素都将被更新。

The "arrayFilters" as passed to the options for .update() or even .updateOne(), .updateMany(), .findOneAndUpdate() or .bulkWrite() method specifies the conditions to match on the identifier given in the update statement. Any elements that match the condition given will be updated.

因为结构是嵌套的,我们实际使用的是多个过滤器,如数组所指定的那样过滤器定义如图所示。标记的标识符用于匹配位置过滤 $ [< identifier>] 语法实际用于语句的更新块。在这种情况下, inner outer 是用于嵌套链指定的每个条件的标识符。

Because the structure is "nested", we actually use "multiple filters" as is specified with an "array" of filter definitions as shown. The marked "identifier" is used in matching against the positional filtered $[<identifier>] syntax actually used in the update block of the statement. In this case inner and outer are the identifiers used for each condition as specified with the nested chain.

这个新的扩展使得嵌套数组内容的更新成为可能,但它并没有真正帮助查询这些数据的实用性,因此同样的警告适用于前面所解释的。

This new expansion makes the update of nested array content possible, but it does not really help with the practicality of "querying" such data, so the same caveats apply as explained earlier.

你通常真的意味着表达属性,即使你的大脑最初认为嵌套,它通常只是对你如何相信以前的关系部分的反应 一起来。实际上你真的需要更多的非规范化。

You typically really "mean" to express as "attributes", even if your brain initially thinks "nesting", it's just usually a reaction to how you believe the "previous relational parts" come together. In reality you really need more denormalization.

另见如何更新多个数组mongodb中的元素,因为这些新的更新运算符实际上匹配并更新了多个数组元素而不仅仅是第一个,这是之前的位置更新操作。

Also see How to Update Multiple Array Elements in mongodb, since these new update operators actually match and update "multiple array elements" rather than just the first, which has been the previous action of positional updates.


注意有点讽刺的是,因为这是在 .update()的options参数中指定的/ code>和类似的方法一样,语法通常与所有最新的发行版驱动程序版本兼容。

NOTE Somewhat ironically, since this is specified in the "options" argument for .update() and like methods, the syntax is generally compatible with all recent release driver versions.

然而,这不是 mongo shell,因为在那里实现该方法的方式(具有讽刺意味的是为了向后兼容性), arrayFilters 参数不被内部识别和删除解析选项的方法,以便与之前的MongoDB服务器版本和leg提供向后兼容性 acy .update() API调用语法。

However this is not true of the mongo shell, since the way the method is implemented there ( "ironically for backward compatibility" ) the arrayFilters argument is not recognized and removed by an internal method that parses the options in order to deliver "backward compatibility" with prior MongoDB server versions and a "legacy" .update() API call syntax.

因此,如果你想在<$中使用该命令c $ c> mongo shell或其他基于shell的产品(特别是Robo 3T)您需要3.6或更高版本的开发分支或生产版本的最新版本。

So if you want to use the command in the mongo shell or other "shell based" products ( notably Robo 3T ) you need a latest version from either the development branch or production release as of 3.6 or greater.

参见 位置所有$ [] ,它还会更新多个数组元素但不适用于指定条件并适用于所有数组中的元素,即所需的操作。

See also positional all $[] which also updates "multiple array elements" but without applying to specified conditions and applies to all elements in the array where that is the desired action.

这篇关于使用MongoDB更新嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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