MongoDB:如果查询对象和更新对象包含相同的属性,则无法upsert,'无法将$ addToSet修饰符应用于非数组'

时间:2014-03-10 19:48:25

标签: regex mongodb updates insert-update upsert

我想执行一个复杂的upsert,由以下元素组成:

  • 通过regex
  • 查询字段 f
  • 更新同一字段 f (也在查询对象中指定)

像这样:

db.coll.update({ prop: /valueprop/i } , { $addToSet:{ prop:'a value' }  } , true, false)

我的期望是,如果文档在集合中不存在,则插入 prop 字段等于'a value';换句话说,它应该插入一个值为 prop 字段的文档,该字段是更新对象中指定的字段。

而是抛出Cannot apply $addToSet modifier to non-array,就像它尝试使用查询对象中指定的值(即RegExp对象)更新字段prop而不是使用更新对象中指定的值。

这不是一个错误吗?

2 个答案:

答案 0 :(得分:1)

解决方法是以下列方式在查询对象中使用$all关键字

db.cancellami.update({prop:{$in:[/regex_value/i]}},{ $addToSet:{prop:'a value'}} ,true,false)

答案 1 :(得分:0)

如文档中所述$ addToSet运算符只有在数值不在数组中时才向数组添加值:http://docs.mongodb.org/manual/reference/operator/update/addToSet/#up._S_addToSet

您的 prop 值是一个字符串,因此您无法使用$ addToSet。而不是这样你可以做下一个:

db.collection.update({prop:/valueprop/i},{$set:{prop:['a value']}}, true, false)

<强>更新 如果您需要确保数组中不存在重复项,则必须首先更新所有文档以将其转换为数组,如下所示:

db.collection.find({ $where : "isString(this.prop)"}).forEach(function (doc) {
       doc.prop = [doc.prop];
       db.collection.save(doc); 
})

然后您将能够执行下一个以确保您始终只更新数组字段并且不会发现任何错误:

db.collection.update({ $where : "Array.isArray(this.prop)"},{$addToSet:{prop:'a value'}}, true, false)