【问题标题】:Mongodb $setOnInsert not working with $max and $minMongodb $setOnInsert 不适用于 $max 和 $min
【发布时间】:2015-09-28 06:07:55
【问题描述】:

我的以下查询在没有 $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){
  ...
});

任何想法将不胜感激。

谢谢。

【问题讨论】:

    标签: javascript node.js mongodb mongoose mongodb-query


    【解决方案1】:

    您的查询确实带有警告,因此实际上只需要解释会出现什么问题。

    首先,您的 MongoDB 服务器版本必须至少为 2.6.x 或更高版本才能使 $min$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 的值相同,或者超出了分别为“较低”或“较高”值的限制,则不会更新任何内容:

    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 或类似的一样。

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

    作为旁注,请注意您也知道您对$addToSet 的期望。以类似的方式,如果完整的对象已经存在,则不会修改任何内容。但是,如果您有一个具有各种键的对象,那么更改这些值中的任何一个都会使整个对象“唯一”并且将添加一个新成员。如果您打算执行其他操作,例如只有“一个”键来包含唯一值,那么您需要应用其他逻辑并且不能简单地使用 $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();
      }
    );
    

    【讨论】:

      猜你喜欢
      • 2017-02-08
      • 2016-10-26
      • 2019-04-15
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-05
      • 2016-11-05
      相关资源
      最近更新 更多