在我的数据库中,我有一个名为'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
}
);
有谁知道为什么?非常感谢! (顺便说一句,我使用的是猫鼬)
答案 0 :(得分:4)
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 ) );
})
返回的“结果”是一个符合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”事件。
答案 1 :(得分:0)
"受影响的数字是更新的文档数,即使新值相同也是如此。这直接来自mongo。"我从这个论坛帖子中得到了这个帖子:https://github.com/LearnBoost/mongoose/issues/867
这意味着在更新之前,您必须提出一种不同的方法来确定数组中是否缺少该元素。我建议在更新之前拉出所有文档并迭代它们。显然它并不理想,但我认为没有其他办法可以做到。
希望这有帮助。