MongoDB-检查$ addToSet是否重复

问题描述 投票:1回答:1

我正在使用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);
});

它的作用:

  1. 如果集合中没有文档,则创建一个并填写所有字段
  2. 如果存在文档,则仅使用新的用户ID更新likes数组

[此操作正常,没有问题,这要感谢$addToSe t我没有任何重复等。

但是在执行了上述代码并返回了result之后,我需要做一些额外的事情,并且要使其正常工作,我需要知道Mongos $addToSet是否确实进行了任何更改。

简而言之:

  1. 如果新的userId已添加到likes数组中,我想做某事
  2. 如果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。

还有更好的主意吗?

javascript node.js mongodb mongodb-query
1个回答
0
投票

我找到了解决方案!

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);
        });
    });
  }

希望这个答案将来会帮助遇到类似问题的人:)

© www.soinside.com 2019 - 2024. All rights reserved.