MongoDB:不正确的更新计数

Mar*_*ria 3 javascript mongoose mongodb node.js

在我的数据库中,我有一个名为“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
    }
);
Run Code Online (Sandbox Code Playgroud)

有谁知道为什么?非常感谢!(顺便说一句,我正在使用猫鼬)

Nei*_*unn 6

mongoose 中的当前方法实现使用遗留的写关注 API 来确定修改文档的数量。如您所见,即使内容没有实际更改,例如$addToSet未向集合添加新成员的操作,也会返回修改后的计数。

只要您的 MongoDB 服务器版本足够新(需要 MongoDB 2.6 或更高版本)并且您的 mongoose 版本足够新并且捆绑了最新的 mongodb 驱动程序,那么您就可以从批量操作 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 ) );
})
Run Code Online (Sandbox Code Playgroud)

返回的“结果”是一个符合BulkWriteResult( ) 规范的对象,它或多或少看起来像这样:

{
   "writeErrors" : [ ],
   "writeConcernErrors" : [ ],
   "nInserted" : 2,
   "nUpserted" : 0,
   "nMatched" : 3,
   "nModified" : 3,
   "nRemoved" : 1,
   "upserted" : [ ]
}
Run Code Online (Sandbox Code Playgroud)

但具体来说,在您使用$addToSet并且成员已经存在的地方,响应将包含"nMatched": 1and "nModified": 0,这是您想要看到的结果,确认实际上没有向集合中添加任何内容。

在 MongoDB 2.6 shell 中,所有更新和插入方法都尝试在此 API 可用的情况下使用它,并且仅在连接到旧服务器时才回退到旧实现。因此,如果您在具有现代服务器的现代 shell 中执行此操作,您将看到相同的结果。

希望 mongoose 本身将被更改为在可用的情况下也使用这些方法并提供对相同响应的访问。这似乎是未来的方式,但代码库尚未赶上并利用它。

注意:在访问集合对象后使用任何本机驱动程序方法时要注意的一件事是确保 mongoose 在调用时具有与数据库的活动连接。Mongoose 通过将任何请求排队直到真正建立连接来隐藏这一点。

因此,如果您直接使用集合对象方法,那么您可能需要确保在该代码执行之前等待某个连接上的“打开”事件。