2016-05-30 34 views
3

我正在嘗試做什麼。

我有一個userSchema其中包含一個operationCountSchema對象的列表。我試圖做的是創建一個靜態方法,如果它存在(由month_id標識)字段,則更新count字段中的某個操作計數子文檔。如果operationCountSchema文檔在當月不存在,它應該創建一個新文檔。有沒有辦法在貓鼬中實現這種行爲?我曾嘗試使用upsert無濟於事。如何做到這一點?謝謝。貓鼬 - 在Subdoc上增加字段如果存在,否則創建新的

CODE

var operationCountSchema = mongoose.Schema({ 
    month_id: String, 
    count: { type: Number, default: 0 } 
}, {_id : false}); 

var userSchema = mongoose.Schema({ 
    username : { type: String, unique: true, required: true }, 
    email: { type: String, unique: true, required: true }, 
    password: String, 
    operation_counts: [operationCountSchema] 
}); 

userSchema.statics.incrementOperationCount = function(userID, callback) { 
    var currDate = new Date(); 
    var dateIdentifier = currDate.getFullYear() + "-" + currDate.getMonth(); 
    //NEED TO INCREMENT OPERATION COUNT IF ONE FOR MONTH EXISTS, 
    //ELSE IF IT DOES NOT EXIST, CREATE A NEW ONE. 
} 

而且,在此功能可以實現替代方式中的任何建議,歡迎。

+0

通過靜態方法傳遞值並檢查子文檔是否存在(使用'this'關鍵字)。如果存在修改和調用回調。否則使用'this.sub-docment = '創建子文檔並調用回調。一旦調用回調函數,使用mongoose文件'save()'方法保存修改過的文檔。 –

+0

'month_id'需要匹配以增加計數值是什麼? – Chinni

+0

@Chinni month_id需要匹配dateIdentifier。 –

回答

1

所以你可以有一個mongoose.find()mongoose.findOne()並檢查子文檔是否存在。如果沒有,我們可以創建一個新對象,如果有,我們可以增加並保存。我在使用mongoose.findOne()。請參閱文檔here

userSchema.statics.incrementOperationCount = function(userID, callback) { 
var currDate = new Date(); 
var dateIdentifier = currDate.getFullYear() + "-" + currDate.getMonth(); 
    //NEED TO INCREMENT OPERATION COUNT IF ONE FOR MONTH EXISTS, 
    //ELSE IF IT DOES NOT EXIST, CREATE A NEW ONE. 
    operationCountSchema.findOne({'month_id': dateIdentifier}, function(err, subDoc) { 
     // If there is an error in finding the document, catch them 
     if(err) { 
      // Handle errors 
      return err; 
     } 
     // If you find a document, increment the `count` and save 
     if(subDoc) { 
      subDoc.count += 1; 
      subDoc.save(function(err2) { 
       if(err2) { 
        // Handle errors 
        return err2; 
       } else { 
        return "Success"; 
       } 
      }); 
     } 
     // If no document is found, create a new one 
     else { 
      // Populate the values to create the object 
      var data = { 
       "month_id": dateIdentifier, 
       "count": 0 
      }; 
      operationCountSchema.create(data, function(err3, subDoc) { 
       if(err3) { 
        // Handle errors 
        return err3; 
       } 
       // Else return success 
       return "Success"; 
      }); 
     } 
    }); 
}; 

讓我知道如果我有你的問題worng或沒有處理的東西。

+0

您沒有解決併發問題或競爭條件。在'findOne'和'save'或'create'之間,另一個可能的數據庫編寫者可能已經更新/創建了計數。 – robertklep

+0

那麼多人有權同時更新相同的文檔記錄? – Chinni

+0

MongoDB完全有可能在''findOne'和'save/create'之間由另一個作者更新文檔,因爲MongoDB沒有事務。 – robertklep

3

我想你想findOneAndUpdate()upsert : true

operationCountSchema.findOneAndUpdate({ 
    month_id : dateIdentifier, 
}, { 
    $inc : { count : 1 } 
}, { 
    upsert : true 
}, callback); 

(未經測試)

+0

我認爲你誤解了我的代碼/問題。 month_id不是唯一的。操作計數模式需要根據用戶查詢它是一個子文檔。 –

+0

@AnthonyDito啊,我以爲你使用了一個單獨的集合,但你使用的是subdocs。在這種情況下,我認爲你不可能一步到位,這意味着任何更新都將容易出現競爭狀況。 – robertklep

2

你可以做的兩個步驟,這裏是mongo shell一個例子:

mongos> db.collection.findOne()  
{ 
    "username" : "mark", 
    "email" : "[email protected]", 
    "password" : "balalalala", 
    "operation_counts" : [ 
     { 
      "month_id" : "2016-05", 
      "count" : 6 
     } 
    ] 
} 

首先,確保subdoc存在,如果不是隻創建一個使用$addToSet

mongos> db.collection.update({username:"mark", "operation_counts.month_id": {$ne:"2016-05"}}, {$addToSet: {"operation_counts":{month_id: "2016-05", count:0}}}) 
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 }) 
// only update when the subdoc of specified month not exists 
mongos> db.collection.update({username:"mark", "operation_counts.month_id": {$ne:"2016-06"}}, {$addToSet: {"operation_counts":{month_id: "2016-06", count:0}}}) 
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) 

mongos> db.collection.findOne() 
{ 
    "_id" : ObjectId("575636c21e9b27fe715df654"), 
    "username" : "mark", 
    "email" : "[email protected]", 
    "password" : "balalalala", 
    "operation_counts" : [ 
     { 
      "month_id" : "2016-05", 
      "count" : 6 
     }, 
     { 
      "month_id" : "2016-06", 
      "count" : 0 
     } 
    ] 
} 

然後,增加count字段。

mongos> db.collection.update({username:"mark", "operation_counts.month_id": "2016-06"}, {$inc:{ "operation_counts.$.count":1 }}) 
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 }) 

mongos> db.collection.findOne() 
{ 
    "_id" : ObjectId("575636c21e9b27fe715df654"), 
    "username" : "mark", 
    "email" : "[email protected]", 
    "password" : "balalalala", 
    "operation_counts" : [ 
     { 
      "month_id" : "2016-05", 
      "count" : 6 
     }, 
     { 
      "month_id" : "2016-06", 
      "count" : 1 
     } 
    ] 
} 
+0

我最終實現了類似的東西。這似乎是最好的解決方案。如現在這樣。我會獎賞你的賞金。 –

+0

恩,我使用'$ ne'運算符來匹配,所以你應該確保其他條件可以使用索引,並且'operation_counts'數組不會太大。 – Shawyeok

相關問題