我可以使用pop()获取Mongoose中最后插入的子文档吗?

时间:2014-09-08 22:45:36

标签: node.js mongodb mongoose

我正在进行findOneAndUpdate调用以使用$addToSet添加到子文档数组。该操作返回新更新的文档。我想提取刚插入的子文档。在这种情况下使用pop()是否安全?我知道浏览器在排序数组/对象方面有所不同,但对节点/ mongo情况不确定。

1 个答案:

答案 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方法,它会为您提供正确的响应,即文档未更新,因为该元素已经是“集合”的一部分。