2017-10-17 10 views
1

いくつかのコレクションで2つまたは3つの異なる操作を実行する必要がある場合は、find/update操作を連鎖させるよりも良い方法はありますか?たとえば、複数のMongoDB操作を行う正しい方法

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

ちょうど乱雑に思えますし、もっとやり方が必要です。さらに、他のupdateが実行されないようにする最初のfindOneAndUpdateの後にエラーがある場合、ドキュメント間で矛盾したデータが存在します。ドキュメントには、参照を高速化するために他のドキュメントへのID参照が含まれています。

また、一連の約束内のすべてのエラーをキャッチする方法はありますか?

答えて

1

あなたのコールバック地獄から、引数を.then()メソッドのどこにも使用しないことがわかります。あなたが別のを実行するために、1つのクエリの結果を必要としない場合は、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

そして、それを実現するために許容される場合に見て1kk回に1回、アプリケーションのロジック内で一貫性をチェックすることを含めましょう。

関連する問題