更新MongoDB中的嵌套对象

时间:2014-06-15 18:22:06

标签: mongodb mongodb-query

我正在尝试更新MongoDB中的嵌套文档,该文档看起来类似于下面的内容(缩写为简洁)。

{
  "cols": "20",
  "saveTime": "2014-06-15-10:44:09",
  "rows": "20",
  "gameID" : "66f2497c-7a2b-4210-a06b-80be0e6a8fd8",
  "players": [
    {
      "id": "Inhuman",
      "num": "1",
      "color": "00ff00ff",
      "name": "badComputer",
      "type": "1"
    },
    <...>
  ],
  "nodes": [
    {
      "g": "1",
      "c": "0",
      "r": "0",
      "a": "0",
      "o": ""
    },
    {
      "g": "1",
      "c": "0",
      "r": "1",
      "a": "0",
      "o": ""
    }
    <...>
  ],
}

我要做的是更新其中一个节点。例如,我想更改节点:

{ "g": "1", "c": "0", "r": "0", "a": "0", "o": ""}

{ "g": "1", "c": "0", "r": "0", "a": "5", "o": ""}

我尝试使用点(。)表示法,使用$ set命令,ala:

db.game.update({"gameID" : "66f2497c-7a2b-4210-a06b-80be0e6a8fd8"}, { $set: {"nodes.r":"0",   "nodes.c":"0", "nodes.a":"5"}}),

但这并没有给我预期的行为,因为我正在使用相同的r和c值更新所有节点。这显然不是我想要的,但我不知道如何更新本文档的特定部分。有谁知道如何做到这一点?

2 个答案:

答案 0 :(得分:1)

如果您要更新&#34;节点&#34;中的特定项目数组,你不知道的位置,但你知道&#34;标准&#34;要匹配该项,那么您需要$elemMatch运算符以及更新方中的positional $运算符:

db.game.update(
    {
        "gameID" : "66f2497c-7a2b-4210-a06b-80be0e6a8fd8",
        "nodes": { "$elemMatch": { "g": 1, "r": 0 } } 
    },
    { "$set": { "nodes.$.c":"0", "nodes.$.a":"5" } }
)

positional $运算符包含匹配的&#34;索引&#34;第一个元素的位置&#34;匹配&#34;根据您的查询条件。如果您不使用$elemMatch并使用&#34;点符号&#34;相反,然后匹配仅对包含值为真的整个文档有效,并且不反映&#34;位置&#34;匹配两个字段条件的元素。

必须注意这是第一个&#34;匹配,通常预期为唯一匹配。原因是位置操作符只包含&#34;第一个&#34;有多个匹配的位置。要以这种方式更新多个符合条件的数组项,则需要多次发出更新,直到文档不再被修改。

对于一个已知的&#34;你可以随时直接使用&#34;点符号&#34;表单,包括您要更新的元素的位置:

db.game.update(
    {
        "gameID" : "66f2497c-7a2b-4210-a06b-80be0e6a8fd8",
    },
    { "$set": { "nodes.0.c":"0", "nodes.0.a":"5" } }
)

因此第一个元素的索引位置为0,第二个元素的索引位置为1,依此类推。

注意在这两种情况下,您只需要传递到$set您想要更改的字段。因此,除非您不确定存在的值(如果这是您的查询,情况就不是这样),那么您不需要设置&#34;字段到它们已经包含的值。

答案 1 :(得分:0)

要更新特定节点 - 您需要将其放在搜索的查询部分。

  db.game.update({"gameID" : "66f2497c-7a2b-4210-a06b-80be0e6a8fd8","nodes.r":"0", 

  "nodes.c":"0", "nodes.a":"5" }, { $set: {"nodes.$.r":"0",   "nodes.$.c":"0", "nodes.$.a":"5"}})

您会看到$ sign将其找到的节点对象与呼叫的第一部分(查询)匹配,并将您发送到呼叫的第二部分(投影)部分。 另外check out this question