2016-05-30 9 views
3

私がやろうとしていること。

userSchemaには、operationCountSchemaオブジェクトのリストが含まれています。私がやろうとしているのは、これらの操作カウントサブ文書が存在する場合(month_id)フィールドのいずれかのcountフィールドを更新する静的メソッドを作成することです。今月のoperationCountSchema文書が存在しない場合は、新しい文書を作成する必要があります。マングースでこの行動を達成する方法はありますか?私はupsertを無駄に使用しようとしました。どのようにこれを行うでしょうか?ありがとう。Mongoose - Subdoc上のインクリメントフィールド(存在する場合)、それ以外は新規作成

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. 
} 

CODEはまた、この機能を実現することができる代替の方法上の任意の提案を歓迎します。

+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したか何かを言わなかったかどうか教えてください。私はあなたがupsert : truefindOneAndUpdate()をしたいと思います

+0

同時実行の問題または競合状態に対処していません。 'findOne'と' save'または 'create'の間には、別のデータベースライターがすでにカウントを更新/作成している可能性があります。 – robertklep

+0

複数の人が同じ文書レコードを同時に更新する権限を持っていますか? – Chinni

+0

MongoDBはトランザクションを持たないので、_ong_ 'findOne'と' save/create'の間に別のライターによってドキュメントが更新されることはMongoDBでは完全に可能です。 – robertklep

3

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

(未テスト)

+0

あなたは私のコード/質問を誤解していると思います。 month_idは一意ではありません。操作数のスキーマは、それがサブ文書であることをユーザーに基づいて照会する必要があります。 –

+0

@AnthonyDitoああ、私は別のコレクションを使っていると思ったが、あなたはサブ文書を使っている。その場合、私はあなたがそれを単一のステップで動かすことはできないと考えています。つまり、更新は競争条件になりがちです。 – robertklep

2

あなたはここで2つのステップでそれを行うことができますがmongo shell例である:

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

まず、 1つの用途を作成するだけではない場合は、サブディレクトリが存在することを確認してください。$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

関連する問題