我正在进行findOneAndUpdate
调用以使用$addToSet
添加到子文档数组。该操作返回新更新的文档。我想提取刚插入的子文档。在这种情况下使用pop()
是否安全?我知道浏览器在排序数组/对象方面有所不同,但对节点/ mongo情况不确定。
答案 0 :(得分:2)
MongoDB中“套装”的一般官方路线是它们不被认为是以任何方式订购的。实际上有一些讨论认为“集合”甚至可能在某些时候构成与普通数组不同的数据类型,但是到目前为止,类型之间没有区别,它们在内部被视为另一个数组。
然而,看起来,一般行为实际上是添加到集合中的任何“新”项确实“附加”到当前元素列表中,因此任何新内容确实是数组中的最后一个元素。并且数组总是保留位置,这是数据类型的一般要点。所以,虽然你的观点基本上是在问:
“最后添加的项目是列表中的最后一项吗?”
然后看起来就是这种情况,尽管给定的情况警告元素的顺序,这通常看起来更多地是关于“内部”排序的表面值,其中在“c”之后添加“a”不会将“a”元素放在列表的第一位,无需另外修改。
但问题也有点“有趣”,因为你基本上是在问:
“我对该套装的最后更新是否出现在最后?”
哪个IMHO似乎真的在问“它是否更新?”,或者我添加的最后一个成员实际更新了“set”或者该元素是否已经存在。在这种情况下,不是要查看最后一个元素是否与您想要添加的元素相同,更好的选择是检查WriteResult并查看文档是否实际被修改。
考虑这个文件:
{
"list": [ "c", "a" ]
}
然后使用Bulk Operations API发布更新以获得结果:
var bulk = Model.collection("settest").initializeOrderedBulkOp();
bulk.find({}).updateOne({ "$addToSet": { "list": "a" } });
bulk.execute(function(err,result) {
console.log( JSON.stringify( result, undefined, 4 ) );
});
会给你这样的东西:
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 0,
"nUpserted" : 0,
"nMatched" : 1,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
增强的响应告诉您,即使1
文档与更新语句匹配,文档本身也没有实际修改,因为$addToSet
操作实际上没有执行任何元素已经存在的操作出现在集合中。
如果你考虑了mongoose .findOneAndUpdate()
方法,它是从基本驱动程序的基本底层.findAndModify()
方法派生的,那么你得到的响应是默认的“修改”文档: / p>
Model.findOneAndUpdate(
{},
{ "$addToSet": { "list": "a" },
function(err,doc) {
console.log( JSON.stringify( doc, undefined, 4 ) );
}
);
所以这基本上和以前一样,没有办法判断更新操作是否真的做了什么。
现在你可以修改它来要求原始文件而不是修改过的文件:
Model.findOneAndUpdate(
{},
{ "$addToSet": { "list": "a" },
{ "new": false },
function(err,doc) {
console.log( JSON.stringify( doc, undefined, 4 ) );
}
);
但是你唯一真正了解的结果是,如果你上次添加的元素不在原始文档中,那么就会导致更新。当然它是“现在”,因为你要求它这样做,操作成功并返回给你一份文件:
Model.findOneAndUpdate(
{},
{ "$addToSet": { "list": "a" },
{ "new": false },
function(err,doc) {
if ( doc.list.indexOf("a") == -1 )
console.log( "updated set" );
}
);
但列表中的“最后一个元素”是否已添加?如前所述,它似乎是这样,但问题是否总是保持不变。但这样做真的没有多大意义,因为你不能保证你刚刚做的操作实际上做了什么而没有正确检查它。
因此,在诸如.findOneAndUpdate()
之类的原子操作中,您获得了返回的文档,或者实际上在任何“更新”变体中,“执行此操作”的更好选项是实际检查写入结果或原始文件是您期望的操作结果。
最后,如果您需要整个文档,请使用.findOneAndUpdate()
但使用“原始文档”选项。您可以放心地假设您的操作成功,并将该元素添加到最初不存在的列表中,如果这是您想要的结果。差异告诉您更新是否真的做了什么。
但是,如果您只想知道是否确实添加了新元素,那么只需使用批量API方法,它会为您提供正确的响应,即文档未更新,因为该元素已经是“集合”的一部分。