MongoDB:更新计数不正确

3

在我的数据库中,我有一个名为“fruits”的字段,它是一个简单的数组。当向此数组插入元素时,我使用$addToSet仅插入尚不存在于该数组中的元素。

我想知道我插入的元素是否真的修改了这个字段。然而,在回调函数中,docModified参数即使我尝试添加一个已经存在的元素,也总是返回1

model.update (
    { username: username }, // find the document
    { $addToSet : { fruits: "apple" } }, // add "apple" to fruits field
    function (err, docModified) {
        console.log(docModified);
        // !PROBLEM: this will print "1" no matter what
    }
);

有人知道原因吗?非常感谢!(顺便说一下我在使用Mongoose)

2个回答

6
当前mongoose中的方法实现使用遗留的写入关注API来确定修改文档的数量。正如您所指出的,即使内容没有实际更改,例如不向集合添加新成员的 $addToSet 操作,也会返回修改后的计数。
只要您的MongoDB服务器版本足够新(需要MongoDB 2.6或更高版本),且mongoose版本足够新并捆绑了最新的mongodb驱动程序,则可以从Bulk Operations API响应中获取正确的数字。
要使用mongoose实现这一点,您需要在模型上调用.collection访问器,该访问器返回一个本机驱动程序集合对象:
var bulk = Model.collection.initializeOrderedBulkOp();
bulk.find({ username: username })
    .updateOne({ $addToSet : { fruits: "apple" } });

bulk.execute(function(err,result) {
    if (err) throw err;

    console.log( JSON.stringify( result, undefined, 4 ) );
})

返回的"result"对象符合BulkWriteResult()规范,大致如下:
{
   "writeErrors" : [ ],
   "writeConcernErrors" : [ ],
   "nInserted" : 2,
   "nUpserted" : 0,
   "nMatched" : 3,
   "nModified" : 3,
   "nRemoved" : 1,
   "upserted" : [ ]
}

但是,具体来说,当您使用$addToSet并且成员已经存在时,响应将包含"nMatched": 1"nModified": 0,这是您希望看到的结果,确认实际上没有添加任何内容到集合中。
在MongoDB 2.6 shell中,所有更新和插入方法都尝试使用此API(如果可用),只有在连接到旧服务器时才回退到旧实现。因此,如果您在现代shell中使用现代服务器执行此操作,则会看到相同的结果。
希望mongoose本身也会在可用的情况下使用这些方法,并提供访问相同响应的方法。这似乎是未来的趋势,但代码库尚未跟上和利用它。
注意:在访问集合对象后使用任何本机驱动程序方法时需要小心,确保mongoose在调用此方法时与数据库建立了活动连接。mongoose通过将任何请求排队等待,直到实际建立连接来隐藏这一点。
因此,如果您直接使用集合对象方法,则可能需要确保在代码执行之前在连接的某个位置等待“open”事件。

谢谢!非常有帮助和详细的回复 :) - Maria

2
"受影响的数量是更新的文档数,即使新值相同。这是直接来自Mongo的。" 我从这个论坛帖子中得到了这个信息:https://github.com/LearnBoost/mongoose/issues/867 这意味着您必须想出一种不同的方法来确定在更新之前数组中是否缺少元素。我建议在更新之前先拉取所有文档并对它们进行迭代。显然这不是理想的,但我认为没有其他办法。
希望这可以帮助到您。"

直接从Mongo来的是mongoose仍然实现的“遗留”响应。但是有一种方法可以确定正确的响应已经实现了几个月,因为它在底层驱动程序中实现了。 - Neil Lunn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接