如果数组存在,则将对象推入数组,否则在MongoDB中创建带有该对象的数组。

18

我有一个包含如下文档的集合:

{
    _id : "abcd",
    name : "Tom",
    myArray : [
        {
            field1 : "",
            field2 : ""
        }
    ]
},
{
    _id : "efgh",
    name : "Jerry"
}

我有一个新对象需要添加到myArray中。我想编写一个查询来仅更新一个文档。

如果查询匹配具有_id : "abcd"的文档,则将新对象推入myArray字段中:

{
    _id : "abcd",
    name : "Tom",
    myArray : [
        {
            field1 : "",
            field2 : ""
        },
        {
            // new object
        }
    ]
}

如果查询与 _id : "efgh" 匹配,则在其中创建一个新对象的 myArray 字段:

{
    _id : "efgh",
    name : "Jerry"
    myArray : [
         {
              // new object
         }
    ]
}

我该怎么实现这个?


你想做什么?将“efgh”中的“myArray”设置为与“abcd”相同的内容?还是想要将新的数组项目推送到“abcd”和“efgh”中?在你的问题上有一个[编辑](http://stackoverflow.com/posts/31770550/edit)链接,你可以添加细节以使你的意图清晰。 - Blakes Seven
@BlakesSeven,修改了问题,希望您能理解... - iamhimadri
你在这里所说的"elseif"仍然不太清楚。你是指要更新"两个"文档,还是只选择更新"一个"文档? - Blakes Seven
不,我不想同时更新两个文档。一次只更新一个文档。 - iamhimadri
你有尝试过这里的任何东西吗?我猜你没有,因为如果你$push一个数组到一个不存在的文档中,它会创建一个新的数组。如果已经存在一个数组,则新的文档将被追加到该数组中。所以要么你根本没有尝试过,要么你的问题中仍然缺少一些关于你真正想做什么的信息。 - Blakes Seven
2个回答

35

为了解释这里的所有可能情况,请考虑每个文档的情况:

如果您要更改的文档如下所示:

{
    "_id": "efgh",
    "name": "Jerry"
}

然后像这样的更新语句:

db.collection.update(
    { "_id": "efgh" },
    { "$push": { "myArray": { "field1": "abc", "field2": "def" } } }
)

导致这个结果:

{
    "_id": "efgh",
    "name": "Jerry",
    "myArray": [
        {
            "field1": "abc",
            "field2": "def"
        }
    ]
}

所以数组已创建并添加了新项。

如果您的文档已经有了这样一个数组:

{
    "_id": "abcd",
    "name": "Tom",
    "myArray": [
        {
            "field1": "",
            "field2": ""
        }
    ]
}

而你基本上是在重复相同的陈述:

db.collection.update(
    { "_id": "abcd" },
    { "$push": { "myArray": { "field1": "abc", "field2": "def" } } }
)

然后将新文档内容附加到现有数组中:

{
    "_id": "abcd",
    "name": "Tom",
    "myArray": [
        {
            "field1": "",
            "field2": ""
        },
        {
            "field1": "abc",
            "field2": "def"
        }
    ]
}

但是,如果您的原始文档具有命名字段,但不是数组,就像这样:

{
    "_id": "efgh",
    "name": "Jerry",
    "myArray": 123
}

通过在查询条件中进行测试并使用$set而确保它不是数组:

db.collection.update(
    { "_id": "efgh", "myArray.0": { "$exists": false } },
    { "$set": { "myArray": [{ "field1": "abc", "field2": "def" }] } }
)

这将安全地覆盖不是数组的元素(点符号表示“myArray.0”代表第一个数组元素,但事实并非如此),使用包含您内容的新数组进行覆盖。结果与原始值相同:

{
    "_id": "efgh",
    "name": "Jerry",
    "myArray": [
        {
            "field1": "abc",
            "field2": "def"
        }
    ]
}

你能否使用 $addToSet 替代 $push,并且它会检查数组中是否包含完全相同的 JSON 文档? - wprins

5

$Push 就是你需要实现这个的方法。 如果 myArray 已经存在,那么 $push 会将新对象插入到其中(类似于 STACK 数据结构操作)。 如果 myArray 不存在,则会创建字段“myArray”作为键,并将新对象插入其中(类似于 $Set 操作)。

考虑下面的另一个示例文档:

{
_id : "abcd"
myArray:[
{
  field1:"mango",
  field2:"apple"
}
       ]
}

现在让我们将以下对象插入其中:

var newObject = {field1:"example1" , field2:"exmaple2"};

查询:

db.collection.update({_id:"abcd"},{"$push":{myArray: newObject }});

在执行以上查询后,结果如下:
{
    _id : "abcd"
    myArray:[
    {
      field1:"mango",
      field2:"apple"
    },
    {
      field1:"example1" , 
      field2:"exmaple2"
    }
           ]
    }

现在让我们考虑另一个例子,即文档中不存在“myArray”键:
{
_id:"efg"
}

所以让我们插入以下对象:
 var newObject2 = { field1 : "exp2" , field2 : "exp1" }

查询:

 db.collection.update({_id:"efg"},{"$push":{myArray: newObject2 }});

以上更新操作的结果如下:
 {
   _id : "efg"
   myArray : [ 
   { 
    field1 : "exp2" , 
    field2 : "exp1"
  }
          ]
}

1
如果我们想要添加一个新文档,但是如果没有该ID的文档可用怎么办? - Rahul_Dabhi
@Rahul_Dabhi 你找到问题的答案了吗?我也想能够做到那样。 - Egor Okhterov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接