簡體   English   中英

如何防止Mongoose允許跨並行請求對文檔進行多次更新?

[英]How can I prevent Mongoose from allowing multiple updates of a document across parallel requests?

給定架構:

{
    widgets: [{
        widget: {type: mongoose.Schema.Types.ObjectId, ref: 'widget'},
        count: {type: Number}
    }]
}

以及申請路線,其中:

  1. 用戶嘗試將新的窗口小部件添加到現有文檔的窗口小部件數組中。
  2. 我們檢查添加的小部件是否滿足某些要求。
  3. 我們將小部件添加到文檔中並保存文檔。

在此設置中,如果我有2個並行請求來執行相同的操作,則兩次都將檢查2次通過,並且文檔將與小部件的2個副本一起保存,即使這在我的業務邏輯中是“非法的”。

異步流如下所示:

  1. Req1命中路線,加載現有文檔
  2. Req2點擊路線,加載現有文檔
  3. Req1檢查文檔條件
  4. Req2檢查文檔條件
  5. Req1嵌入新的小部件,保存文檔
  6. Req2嵌入新的小部件,保存文檔

我以為文檔版本控制( __v )可以像過去一樣為我解決此問題,但是顯然我從不理解這一點,因為兩個請求都按順序運行,並且調試器顯示兩個版本中的文檔版本均為X -save狀態,X + 1處於后保存狀態。 我不明白為什么這不會引發版本錯誤。

我認為這是要解決的異步問題,不一定嚴格地是Mongoose,因此已被標記。

編輯:這有效,但似乎非常冗長:

model
    .findOneAndUpdate({
        _id: doc._id,
        __v: doc.__v
    },
    {
        $push: {
            widgets: {
                widget: widget_id,
                qty: 1
            }
        },
        $inc: {
            __v: 1
        }
    },
    function(err, doc) {
        // ...
    });

另外,很遺憾,我無法更改現有文檔,然后在其上運行save()方法。

我的搜索發現了此錯誤 ,其中使用此方法時versionKey不會自動增加。 我想我真的不太了解versionKey

看一下對versionKey屬性的解釋(如果還沒有的話)

http://aaronheckmann.tumblr.com/post/48943525537/mongoose-v3-part-1-versioning

本文中的示例與您的示例相似,不同之處在於它們正在修改數組項(注釋),並且您將新項推送到小部件數組。 但是據我了解,如果您使用貓鼬v3 +並執行save()操作,那么它將為您執行所有必要的versionKey操作。

因此,如果您將執行以下操作:

model.findById(doc._id, function(err, doc) {
  // handle error
  doc.widgets.push({ widget: widget_id, count: widget_count });
  doc.save(callback);
});

然后save()操作在內部應如下所示:

doc.update(
  { _id: doc._id, __v: doc.__v },
  { 
    $push: { 
      widgets: { widget: widget_id, count: widget_count } 
    },
    $inc: {
      __v: 1
    }
  }
);

因此,也許您應該確保使用貓鼬v3 +並先執行push()然后再執行save(),或者這是您最初如何執行此操作的?

我尚未對此進行測試,只是想與您分享我的搜索結果和想法,以防萬一。

然后,也許您可​​以嘗試添加小部件以檢查更新查詢:

model.findById(doc._id, function(err, doc) {
  // handle error

  // on update query check if there is no such widget in widgets array
  doc.update(
    { _id: doc._id, { 'widgets.widget': { $nin: [widget_id] } }},
    { 
      $push: { 
        widgets: { widget: widget_id, count: widget_count } 
      }
    }
  );
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM