执行多个MongoDB操作的正确方法

时间:2017-10-17 12:07:36

标签: javascript node.js mongodb express

如果我需要对几个集合执行两个或三个不同的操作,有没有比将find/update操作链接在一起更好的方法?例如:

db.collection('contactinfos').findOneAndUpdate(
  { _id: ObjectID(contactID) },
  { $set: { sharedWith } }
).then(response => {
  db.collection('users').update(
    { _id: { $in: sharedWith.map(id => ObjectID(id)) } },
    { $addToSet: { hasAccessTo: contactID } },
    { multi: true }
  ).then(response => {
    db.collection('users').update(
      { _id: { $in: notSharedWith.map(id => ObjectID(id)) } },
      { $pull: { hasAccessTo: contactID } },
      { multi: true }
    ).then(response => {
      return res.send({ success: true });
    }).catch(err => {
      logger.error(`in updating sharing permissions for ${contactID} by user ${_id}`, err);
      return res.status(400).send({ reason: 'unknown' });
    });
  }).catch(err => {
    logger.error(`in updating sharing permissions for ${contactID} by user ${_id}`, err);
    return res.status(400).send({ reason: 'unknown' });
  });
}).catch(err => {
  logger.error(`in updating sharing permissions for ${contactID} by user ${_id}`, err);
  return res.status(400).send({ reason: 'unknown' });
});

它看起来很混乱,必须有一些更好的方法。此外,如果在阻止其他findOneAndUpdate运行的第一个update之后出现错误,则跨文档的数据将不一致。这些文档包含对其他文档的ID引用,以便更快地查找。

此外,有没有办法捕捉承诺链中的所有错误?

1 个答案:

答案 0 :(得分:1)

从你的回调地狱我可以看到你不在任何地方使用response方法的.then()参数。如果您不需要一个查询的结果来执行另一个查询,请考虑使用Promise.all()方法:

const updateContactInfo = db.collection('contactinfos')
    .findOneAndUpdate(
        { _id: ObjectID(contactID) }, 
        { $set: { sharedWith } }
    );
const updateUsers = db.collection('users')
    .update(
        { _id: { $in: sharedWith.map(id => ObjectID(id)) } }, //hint: use .map(ObjectId) instead.
        { $addToSet: { hasAccessTo: contactID } },
        { multi: true }
    );
const updateUsers2 = db.collection('users')
    .update(
        { _id: { $in: notSharedWith.map(id => ObjectID(id)) } }, //hint: use .map(ObjectId) instead.
        { $pull: { hasAccessTo: contactID } },
        { multi: true }
    );

Promise
    .all([updateContactInfo, updateUsers, updateUsers2])
    .then((values) => {

        const updateContactInfoResult = values[0];
        const updateUsersResult       = values[1];
        const updateUsers2Result      = values[2];

        return res.send({ success: true });

    })
    .catch((reason) => {

        logger.error(`msg`, reason);
        return res.status(400).send({ reason: 'unknown' });

    });
只有当所有承诺都解决后,

Promise.all()才会继续执行.then(),否则它将落入.catch()方法。在错误处理方面,您可以轻松地链接多个.catch()方法,这很好地解释了here

如果您不能有任何数据不一致,请:

  1. 获取一些带有事务的SQL数据库(更简单的解决方案)
  2. 查看MongoDB Two-Phase Commit
  3. 如果可以接受,请每1kk次说一次,确保在应用程序的逻辑中检查它的一致性。