我正在使用MongoDB为我的应用程序创建类似功能。我最近偶然发现一个问题。
我喜欢的代码:
async function like(articleId, userId) {
const db = await makeDb();
return new Promise((resolve, reject) => {
const result = db.collection(collectionName).findOneAndUpdate(
{ articleId: ObjectID(articleId) },
{
$setOnInsert: {
articleId: ObjectID(articleId),
creationDate: new Date()
},
$addToSet: { likes: ObjectID(userId) }
},
{ upsert: true }
);
resolve(result);
});
它能做什么:
如果集合中没有文档,则创建一个并填写所有字段
如果存在文档,则仅使用新的用户ID更新
likes
数组这可以按预期工作,并且没有问题,这要感谢
$addToSe
t我没有任何重复等。但是,在执行了上面的代码并返回了
result
之后,我需要做一些其他的事情,并且要使其正常工作,我需要知道Mongos $addToSet
是否确实进行了任何更改。简而言之:
如果新的userId已添加到
likes
数组中,我想做点什么如果userId已经在
likes
数组中,并且$addToSet
没有更改任何内容,我不想采取任何措施。有没有办法区分
$addToSet
是否做了什么?结果的当前
console.log()
如下所示: {
lastErrorObject: { n: 1, updatedExisting: true },
value: { _id: 5e2c47c57bb5183d80dce14f,
articleId: 5da4d1365217baf52fbcd76a,
creationDate: 2020-01-25T13:51:01.928Z,
likes: [ 5d750b677d8edfc08af8a527 ]
},
ok: 1
}
我想到的一件事(但是在性能方面非常差)是如果更新
likes
数组包含带有javascript includes
方法的userID,则在更新之前将其进行比较。还有更好的主意吗?
最佳答案
我找到了解决方案!
99%的功劳归给Neil Lunn
这个答案:
https://stackoverflow.com/a/44994382/2175228
它使我走上了正确的道路。我放弃了findOneAndUpdate
方法,转而使用updateOne
方法。查询参数等都保持不变,只是方法名称发生了变化,显然该方法的结果类型也是如此。updateOne
方法的问题在于它不返回已更新的对象(或旧的对象)。但是它确实返回upsertedId
,这是我所需要的唯一内容。
因此,最终您得到的是一个很长的CommandResult
对象,该对象以:
CommandResult {
result: { n: 1, nModified: 0, ok: 1 },
(...)
}
但是当我仔细观察时,我发现该对象正是我一直需要的那些字段:
modifiedCount: 0,
upsertedId: null, // if object was inserted, this field will contain it's ID
upsertedCount: 0,
matchedCount: 1
因此,您需要做的就是从
CommandResult
对象中获取所需的部分,然后继续;)我的代码更改后:
async function like(articleId, userId) {
const db = await makeDb();
return new Promise((resolve, reject) => {
db.collection(collectionName)
.updateOne(
{ articleId: ObjectID(articleId) },
{
$setOnInsert: {
articleId: ObjectID(articleId),
creationDate: new Date()
},
$addToSet: { likes: ObjectID(userId) }
},
{ upsert: true }
)
.then(data => {
// wrap the content that You need
const result = {
upsertedId: data.upsertedId,
upsertedCount: data.upsertedCount,
modifiedCount: data.modifiedCount
};
resolve(result);
});
});
}
希望这个答案将来可以帮助有类似问题的人:)