做多个MongoDB操作的正确方法
如果我需要在less数集合上执行两三个不同的操作,有没有比链接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引用,以加快查找速度。
另外,有没有办法在承诺链中捕捉到所有错误?
从你的callback地狱,我可以看到你不使用任何地方.then()
方法的response
参数。 如果您不需要一个查询的结果来执行另一个查询,请考虑使用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()
将继续执行Promise.all()
.then()
只有当所有的promise都解决了,否则它将落入.catch()
方法。 从error handling的.catch()
,您可以轻松地链接多个.catch()
方法,这在这里很好的解释。
如果您不能有任何数据不一致,则可以:
- 用事务获取一些SQL数据库
- 研究MongoDB两阶段提交
如果可以接受的话,让我们说每1kk一次,包括检查你的应用程序逻辑中的一致性。