2016-05-30 60 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