为什么用$ addToSet更新返回总是1

时间:2014-06-19 18:10:33

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

我正在使用mongoose,当我按以下方式进行更新时

model.update({_id: id}, {$addToSet: {refs: refId}}, function(err, numAffected){
  console.log(numAffected);
})

这是有效的,如果元素已经在数组中但是numAffected总是1,我的引用不会更新。

这是正确的行为吗?因为它对我没有意义。如果元素未被修改,则numAffected应为0。

有没有办法按我的意愿完成或使用这个库?

提前致谢。

1 个答案:

答案 0 :(得分:4)

原因是mongoose还没有更新,以便在MongoDB 2.6版本中执行与mongo shell相同的操作。

MongoDB 2.6版本引入了批量操作API,它实际上有关于写入关注响应的扩展统计信息。已更新诸如“update”,“insert”和“remove”之类的shell命令,以在其实现中实际使用此API。实际上,你可以通过调用没有结束括号的方法来在shell中看到这个:

db.collection.update

这显示了包含所实现的API方法的代码以及当前由mongoose使用的“遗留”写入关注响应模式的“后备”。

如果您的mongoose版本足够新,捆绑的节点本机驱动程序将支持这些操作。但是您必须通过从Model或其他方式访问.collection方法来引用原始集合对象。您还必须确保数据库连接实际处于活动状态。我在这里强制执行此操作,例如将代码放在连接的“open”事件中:

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

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

var testSchema = new Schema({
  user: String,
  list: []
});

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

mongoose.connection.on("open",function(err,conn) {

  var batch = Test.collection.initializeOrderedBulkOp();

  batch.find({ "user": "me"}).upsert().updateOne({ "$addToSet": { "list": 7 }});

  batch.execute(function(err,result) {
    console.log( JSON.stringify( result, undefined, 4 ) );
  });

});

这对第一次更新操作的响应,并假设已存在一个将匹配的文档,显示该操作的扩展统计信息,其中包含“mMatched”和“nModified”中的单数计数器:

{
    "ok": 1,
    "writeErrors": [],
    "writeConcernErrors": [],
    "nInserted": 0,
    "nUpserted": 0,
    "nMatched": 1,
    "nModified": 1,
    "nRemoved": 0,
    "upserted": []
}

如果这是“upsert”,则计数器将处于“nUpserted”状态,并且统计信息中的“upserted”数组将保存已创建文档的_id

在第二次迭代中,响应将指示文档实际上是“匹配的”但未执行更新:

{
    "ok": 1,
    "writeErrors": [],
    "writeConcernErrors": [],
    "nInserted": 0,
    "nUpserted": 0,
    "nMatched": 1,
    "nModified": 0,
    "nRemoved": 0,
    "upserted": []
}

这是此API提供的新统计信息。 “猫鼬”方法目前使用的“遗留”实现没有做出这种区分。因此,不会返回任何“更新/修改”实际发生。

因此,如果您的版本最近足以支持此功能,那么您可以实现完全如上所示的代码。我希望当前的维护者能够意识到实现的变化,并且会努力让mongoose方法完全按照“引擎盖”的方式完成,就像实现shell辅助方法一样。