2015-09-29 44 views
-1

我試圖實現電子郵件通知功能。我有一個通知的集合,其中每個文檔有以下幾點:以原子方式查找和更新多個文檔

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

然而我找不到一種方法來獲取相關的通知,並以原子方式將其標記爲「通過電子郵件發送」,以便如果此代碼在同一時間在多個服務器上執行,則用戶不會收到競爭狀態多封電子郵件。

任何想法?

+0

不要在頻道上提問,請在頻道上提問。 –

+0

@CrimsonTulip:用這麼多信息填充IRC頻道看起來很垃圾! –

回答

1

以下問題和答案是非常有幫助的:Solution to Bulk FindAndModify in MongoDB

這裏是我的解決方案:

  1. String emailID場更換Boolean emailed領域。爲每臺機器/閱讀器分配一個唯一生成的ID,emailID。
  2. 找到所有相關通知
  3. 與更新他們的:

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

  4. 查找與EMAILID組通知。

的訣竅是用$隔離:真,要麼全寫會發生或沒有它。因此,如果其他讀者已使用其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誰downvoted一個格式良好的問題,沒有指明任何正當的理由。希望這可以幫助別人。