MongoDB setOnInsert和push如果已经存在

时间:2014-02-15 23:19:24

标签: mongodb upsert database

我想添加一个文件,如果它不存在,或者在其中一个子文档中添加一个元素。

db.test.update(
  {
    name : 'Peter'
  },
  $setOnInsert : { 
      name : 'Peter', 
      visits: { 'en' : ['today'], 'us' : [] }
  },
  $push : {
      visits.en : 'today'
  },
  { upsert : true }
)

如果存在Peter,请在其visists.envisists.us数组中添加元素。否则,为Peter创建一个文档。该文档应具有visits的格式,该格式应包含当前元素('today')。

我的问题是我有"have conflicting mods in update"。 即(afaik),我不能在一个查询中写两件事。但我怎样才能解决这个难题?

2 个答案:

答案 0 :(得分:7)

您可以在没有$setOnInsert运算符的情况下实现它。

db.test.update(
  {
    name : 'Peter'
  },
  {
    $push : {
      "visits.en" : 'today'
    }
  },
  { upsert : true }
)

如果Peter存在,则元素'today'将添加到其visits.en数组中。否则,将为Peter创建一个文档,其中包含visits对象,该文档将包含带有en元素的数组'today'。 我认为,由于您在两个操作(visits$setOnInsert)中使用相同的属性($push),因此发生了错误。

答案 1 :(得分:0)

您仍然可以使用$setOnInsert,但$setOnInsert$push未在与之前提及的相同字段中更新。

N.b:如果您不想在数组中使用重复值,我们会使用$addToSet

db.test.update(
    {
      name : 'Peter'
    }, 
     {
      $setOnInsert: {name : 'Peter'},
      $addToSet: {"visits.en": 'today'} // or $push
     },
     {upsert: true})

来自Node.js :我这样做,但你仍然可以直接使用查询。

我这样做的原因是不要使用错误的字段名称插入记录并组织我的更新查询。

首先,您需要创建架构的实例。

 var testSchema = require(./path/testSchema.js);   // require your schema 
 var test = conn.model("test", testSchema, "test"); //conn is the mongoose connection object to the DB
 var testToCreate = new test();
 testToCreate.name : 'Peter' //add fields to the instance

  var testToUpsert = testToCreate.toObject();
  delete testToUpsert._id; 
  delete testToUpsert.visits;

其次,在为模式创建实例时,默认情况下会生成_id属性并且它是唯一的,因此我们需要将其从实例中删除,以便$setOnInsert函数正确,我们删除了访问数组将$addToSet(或$push)与$setOnInsert一起使用时,有两个影响同一字段的查询。

  var options = {
    upsert: true
  };

  test.update({
      name : 'Peter'
    }, {
      $setOnInsert: testToUpsert,
      $addToSet: {
        "visits.en":'today'
      }
    },
    options,
    function(err, testAffected) {
      if (err) {
        return console.error(err);
      }
      console.log('testAffected! :', testAffected);
    });