Mongodb $setOnInsert 不适用于 $max 和 $min

Mongodb $setOnInsert not working with $max and $min

我有以下查询在没有 $max$min 的情况下工作正常,但是,当包含 $max$min 时没有任何反应?

Summary.update({
  productId: _product._id,
},{
  $addToSet: { 
    attrs: _variant.attrs,
    vars: {
      variantId: _variant._id,
      title: _variant.title,
      imgs: _variant.imgs,
    } 
  },
  $max: { 'price.highest': _price.highest },
  $min: { 'price.lowest': _price.lowest },
  $setOnInsert: self.summary
},{
  upsert: true
},function(err,update){
  ...
});

如有任何想法,我们将不胜感激。

谢谢。

您的查询确实附带了警告,因此实际上只是解释出了什么问题。

首先也是最重要的是,您的 MongoDB 服务器版本必须至少为版本 2。6.x 或更高版本才能使 $min and $max 更新运算符可用。

现在考虑基本测试条件:

> db.test.update(
    { "a": 1 },
    { 
        "$setOnInsert": { "b": 2 },
        "$min": { "c": 1 }, 
        "$max": { "d": 1 } 
    },
    { "upsert": true }
  )
WriteResult({
    "nMatched" : 0,
    "nUpserted" : 1,
    "nModified" : 0,
    "_id" : ObjectId("559f114dbe78f212535e2f5f")
})

在第一次执行时,由于没有匹配值 "a" 的数据,因此执行 upsert 在集合中创建新对象:

{
    "_id" : ObjectId("559f114dbe78f212535e2f5f"),
    "a" : 1,
    "d" : 1,
    "c" : 1,
    "b" : 2,
}

现在,如果您更改 $min$max 的值,预期的行为是修改值在约束范围内的那些字段,如下所示:

> db.test.update(
    { "a": 1 },
    { 
        "$setOnInsert": { "b": 3 }, 
        "$min": { "c": 2 },
        "$max": { "d": 2 }
    },
    { "upsert": true }
  )
  WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })

由于 $min 的值大于存储的值,因此该字段未更改。但是 $max 的值大于存储的值并且被修改。 $setOnInsert 中有一个不同的值,但这不会影响数据,因为这次操作不是 upsert

{
    "_id" : ObjectId("559f114dbe78f212535e2f5f"),
    "a" : 1,
    "d" : 2,
    "c" : 1,
    "b" : 2
}

如果您随后发出一个语句,其中 $min$max 具有相同的值,或者不属于 "lower" 或 "higher" 的限制值,则不会更新任何内容:

db.test.update(
    { "a": 1 },
    { 
        "$setOnInsert": { "b": 3 },
        "$min": { "c": 2 }, 
        "$max": { "d": 2 } 
    },
    { "upsert": true }
)
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

这是运营商在此上下文中的预期行为。当然,如果您在尚不存在的字段上提交 $min$max,则该字段将被添加到具有指定值的文档中,就像 $set$push 或类似的。

因此,要么您提交的值不符合更新要求,要么您支持的服务器 and/or 驱动程序版本无法处理运算符。这些都是您需要检查的所有内容,以了解您认为自己没有获得预期结果的原因。

作为旁注,请注意您也知道您对 $addToSet 的期望。以类似的方式,如果完整的对象已经存在,则不会修改任何内容。但是,如果您像您一样拥有一个具有各种键的对象,那么更改这些值中的任何一个都会使整个对象 "unique" 并且将添加一个新成员。如果你想做其他事情,比如只有 "one" 个键来包含唯一值,那么你需要应用其他逻辑,不能简单地使用 $addToSet 来处理它。

此外,除了上述测试条件外,这里还有一个完整列表,您可以 运行 使用 node 和 mongoose。这是针对 MongoDB 3.x 和 mongoose 4.0.6:

测试的
var async = require('async'),
    mongoose = require('mongoose'),
    Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/test');

var testSchema = new Schema({
  "a": Number,
  "b": Number,
  "c": Number,
  "d": Number
});

var Test = mongoose.model('Test',testSchema,"test");


async.series(
  [
    function(callback) {
      Test.remove({},callback);
    },
    function(callback) {
      Test.findOneAndUpdate(
        { "a": 1 },
        {
          "$setOnInsert": { "b": 2 },
          "$min": { "c": 1 },
          "$max": { "d": 1 }
        },
        { "upsert": true, "new": true },
        callback
      );
    },
    function(callback) {
      Test.findOneAndUpdate(
        { "a": 1 },
        {
          "$setOnInsert": { "b": 3 },
          "$min": { "c": 2 },
          "$max": { "d": 2 }
        },
        { "upsert": true, "new": true },
        callback
      );
    },
    function(callback) {
      Test.findOneAndUpdate(
        { "a": 1 },
        {
          "$setOnInsert": { "b": 3 },
          "$min": { "c": 2 },
          "$max": { "d": 2 }
        },
        { "upsert": true, "new": true },
        callback
      );
    }
  ],
  function(err,results) {
    if (err) throw err;
    console.log( JSON.stringify( results, undefined, 2 ) );
    process.exit();
  }
);