以原子方式查找和更新多个文档

时间:2015-09-29 19:52:55

标签: node.js mongodb mongoose

我正在尝试实施电子邮件通知功能。我有一个通知集合,其中每个文档都有以下内容:

{
  userID: {type: ObjectId, index: true, required: true},
  read: {type: Boolean, default: false, index: true},
  emailed: {type: Boolean, default: false, index: true},
}

我有一个节点CronJob,每天一次调用一个应该执行以下操作的函数(伪代码):

foreach (user)
  db.notifications.find({
    userID: user._id,
    read: false,
    emailed: false
  }, function(e, notifications) {
    set emailed to true
    sendNotificationsEmail(user, notifications)
  });

但是,我无法找到一种获取相关通知的方法,并将它们标记为以原子方式“通过电子邮件发送”,这样如果此代码同时在多个服务器上执行,则不会出现竞争条件用户收到多封电子邮件的地方。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

以下问答非常有用:Solution to Bulk FindAndModify in MongoDB

这是我的解决方案:

  1. Boolean emailed字段替换为String emailID字段。为每台机器/阅读器提供唯一生成的ID,emailID。
  2. 查找所有相关通知
  3. 用以下内容更新它们:

    db.notifications.update( {_id: {$in: notificationIDs}, emailID: null, $isolated: true}, {$set: {emailID: emailID}}, {multi: true}

  4. 使用emailID设置查找通知。

  5. 诀窍是,使用$ isolated:true,整个写入都会发生,或者都不会发生。因此,如果其他读者已经使用其emailID声明了通知,那么此更新将不会通过,您可以保证一个读者的更新将在另一个读者更新之前完成。

    findEmailNotifications: function(user, emailID, callback) {
      Notification.find({
        read: false,
        deleted: false,
        userID: user._id,
        emailID: null,
      }, function(findError, notifications) {
        // handle findError
    
        var notificationIDs = getKeys(notifications, '_id');
        if (notificationIDs.length === 0) {
          callback(null, []);
          return;
        }
    
        Notification.update(
          {_id: {$in: notificationIDs}, emailID: null, $isolated: true},
          {$set: {emailID: emailID}},
          {multi: true},
          function(updateError) {
            // handle updateError
    
            Notification.find({
              read: false,
              deleted: false,
              userID: user._id,
              emailID: emailID
            }, function(findError, notifications) {
              // handle findError
    
              callback(null, notifications);
            });
          }
        );
      });
    },
    

    不,谢谢那些在没有说明任何正当理由的情况下对一个结构良好的问题进行投票的downvoters。希望这有助于其他人。