What I am trying to do.
I have a userSchema
that contains a list of operationCountSchema
objects. What I am trying to do, is to create a static method that updates the count
field on one of these operation count subdocuments if it exists (identified by a month_id
) field. If an operationCountSchema
document does not exist for the current month, it should create a new document. Is there a way to achieve this behaviour in mongoose? I have tried using upsert to no avail. How would one do this? Thanks.
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.
}
Also, any suggestions on alternative ways in which this functionality can be achieved are wele.
What I am trying to do.
I have a userSchema
that contains a list of operationCountSchema
objects. What I am trying to do, is to create a static method that updates the count
field on one of these operation count subdocuments if it exists (identified by a month_id
) field. If an operationCountSchema
document does not exist for the current month, it should create a new document. Is there a way to achieve this behaviour in mongoose? I have tried using upsert to no avail. How would one do this? Thanks.
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.
}
Also, any suggestions on alternative ways in which this functionality can be achieved are wele.
Share Improve this question edited Jun 7, 2016 at 3:22 Anthony Dito asked May 30, 2016 at 5:34 Anthony DitoAnthony Dito 3,6803 gold badges33 silver badges59 bronze badges 3-
Pass the values through static method and check whether the sub-document exist(using
this
keyword). If exist modify and call callback. Else create sub-document usingthis.sub-docment = <your-values>
and call the callback. Once the callback is called use mongoose documentsave()
method to save modified document. – n_rao Commented Jun 2, 2016 at 12:58 -
What does
month_id
needs to match to to increment the count? – Chinni Commented Jun 2, 2016 at 19:30 - @Chinni month_id needs to match dateIdentifier. – Anthony Dito Commented Jun 2, 2016 at 23:05
3 Answers
Reset to default 7I think you want findOneAndUpdate()
with upsert : true
:
operationCountSchema.findOneAndUpdate({
month_id : dateIdentifier,
}, {
$inc : { count : 1 }
}, {
upsert : true
}, callback);
(untested)
You can do it in two steps, here is a example in mongo shell
:
mongos> db.collection.findOne()
{
"username" : "mark",
"email" : "[email protected]",
"password" : "balalalala",
"operation_counts" : [
{
"month_id" : "2016-05",
"count" : 6
}
]
}
First, make sure the subdoc exists, if not just create one use $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
}
]
}
Then, increment the count
field.
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
}
]
}
So you can have a mongoose.find()
or mongoose.findOne()
and check if the sub-document exists. If it doesn't we can create the a new object and if it does, we can increment and save.
Here I'm using mongoose.findOne()
. Refer to the docs 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";
});
}
});
};
Let me know if I got your question worng or didn't address something.