您的查询确实带有警告,因此实际上只需要解释会出现什么问题。
首先,您的 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();
}
);