How do I update/upsert a document in Mongoose?
Well, I waited long enough and no answer. Finally gave up the whole update/upsert approach and went with:
ContactSchema.findOne({phone: request.phone}, function(err, contact) {
if(!err) {
if(!contact) {
contact = new ContactSchema();
contact.phone = request.phone;
}
contact.status = request.status;
contact.save(function(err) {
if(!err) {
console.log("contact " + contact.phone + " created at " + contact.createdAt + " updated at " + contact.updatedAt);
}
else {
console.log("Error: could not save contact " + contact.phone);
}
});
}
});
Does it work? Yep. Am I happy with this? Probably not. 2 DB calls instead of one.
Hopefully a future Mongoose implementation would come up with a Model.upsert
function.
Mongoose update/upsert?
var reg_handler = function (act) {
UserModel.update({ $or: [{nick: act.nick}, {hmask: act.host}] }, { $set: { lastfm: act.params } }, { upsert: true }, function(){});
};
This does exactly what I wanted, and it's one line. :D Perfect!
mongoose to determine update-upsert is doing insert or update
The .update()
method in mongoose takes three arguments to the callback, being err
, the numAffected
, and a raw
response. Use the "raw" object to see what happened:
Member.update({user_id : 1},
{$set : {name:"name1"}},
{upsert : true },
function (err, numAffected, raw) {
if (!err) {
console.log(raw)
}
});
You'll see a structure like this:
{ ok: true,
n: 1,
updatedExisting: false,
upserted: [ { index: 0, _id: 5456fc7738209001a6b5e1be } ] }
So there is always the n
and 'updatedExistingkeys available, where the second is false on upserts and true otherwise.
upsertedwill contain the
_id` values of any new documents created.
As for n
or the "numAffected", this is basically always 1 where a document was matched under the legacy write concern responses.
You can see the new WriteResult response in MongoDB 2.6 and above using the Bulk Operations form:
var bulk = Member.collection.initializeOrderedBulkOp();
bulk.find({user_id : 1}.upsert().update({$set : {name:"name1"}});
bulk.execute(err,result) {
console.log( JSON.stringify( result, undefined, 2 ) );
}
Which on a first iteration you get something like this:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"nInserted": 0,
"nUpserted": 1,
"nMatched": 0,
"nModified": 0,
"nRemoved": 0,
"upserted": [
{
"index": 0,
"_id": "5456fff138209001a6b5e1c0"
}
]
}
And a second with the same parameters like this:
{
"ok": 1,
"writeErrors": [],
"writeConcernErrors": [],
"nInserted": 0,
"nUpserted": 0,
"nMatched": 1,
"nModified": 0,
"nRemoved": 0,
"upserted": []
}
And the document would only be marked as "modified" where something was actually changed.
So at any rate, .update()
operations do not return the modified document or the original document. That is the .findOneAndUpdate()
method, a mongoose wrapper around the basic .findAndModify()
which performs an atomic operation. The .update()
methods are typically meant for bulk operations and as such do not return document content.
Save Or Update Mongoose
I think what you're looking for is called an 'upsert'.
You can do this by using findOneAndUpdate and passing the { upsert: true } option, something like the below example:
let campaign = new Campaign({
title: req.body.title,
market: req.body.market,
logo: req.body.logo,
additional_question_information: question,
status: status
});
Campaign.findOneAndUpdate({
_id: mongoose.Types.ObjectId('CAMPAIGN ID TO SEARCH FOR')
}, campaign, { upsert: true }, function(err, res) {
// Deal with the response data/error
});
The first parameter to findOneAndUpdate is the query used to see if you're saving a new document or updating an existing one. If you want to return the modified document in the response data then you can also add the { new: true }
option.
Documentation here for findOneAndUpdate: http://mongoosejs.com/docs/api.html#model_Model.findOneAndUpdate
Update MongoDB document with its own fields
Maybe like this
db.collection.updateOne({ _id }, [
{
$set: {
popularityIndex: {
$sum: [
{ $multiply: [ "$views.count", 0.3 ] },
{ $multiply: [ "$upVoted.count", 0.3 ] },
{ $multiply: [ "$downVoted.count", -0.2 ] },
{ $multiply: [ { $dateDiff: { startDate: "$creationDate", endDate: "$$NOW", unit: "second" } }, -0.2 ] }
]
}
}
}
])
Mongo Playground
Related Topics
Cors - How Do 'Preflight' an Httprequest
Google Maps V3 - Limit Viewable Area and Zoom Level
Fast Stable Sorting Algorithm Implementation in JavaScript
What Limitations Apply to Opaque Responses
Changing Iframe Src with JavaScript
New Date() Is Working in Chrome But Not Firefox
Is There a Max Number of Arguments JavaScript Functions Can Accept
What Are the Common Defenses Against Xss
Asynchronous Exception Handling with Bluebird Promises
Document.Getelementbyid VS Jquery $()
How to Update/Upsert a Document in Mongoose
Why Doesn't JavaScript Support Multithreading
How to Get JavaScript Caller Function Line Number and Caller Source Url
How to Remove an Item from an Array in Angularjs Scope