[MongoDB]: Save vs Insert & Save vs Update
For save, if you provide _id, it will update. If you don’t, it will insert.
To elaborate, if a document does not exist with the specified _id value, the save() method performs an insert with the specified fields in the document.
If a document exists with the specified _id value, the save() method performs an update, replacing all field in the existing record with the fields from the document.
From this, we can say that save is a wrapper for update and insert.
Functionally, save and insert are very similar, especially if no _id value is passed.
However, if an _id key is passed, save() will update the document, while insert() will throw a duplicate key error.
Please see below illustration to make you understand this better.
[root@dbversity]# mongo dbversity –quiet
>
> db.mycol.find()
>
> // When we don’t pass _id value
>
> db.mycol.insert({name:’insert’})
WriteResult({ “nInserted” : 1 })
>
> db.mycol.save({name:’save’})
WriteResult({ “nInserted” : 1 })
>
> db.mycol.find()
{ “_id” : ObjectId(“5c05688042e9152c0cd3848f”), “name” : “insert” }
{ “_id” : ObjectId(“5c05688d42e9152c0cd38490”), “name” : “save” }
>
> // when we pass _id value
>
> db.mycol.insert({_id:1, name:’newrecord’})
WriteResult({ “nInserted” : 1 })
>
> db.mycol.insert({_id:1, name:’newrecord’})
WriteResult({
“nInserted” : 0,
“writeError” : {
“code” : 11000,
“errmsg” : “E11000 duplicate key error collection: dbversity.mycol index: _id_ dup key: { : 1.0 }”
}
})
>
> db.mycol.save({_id:1, name:’newrecord’})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 0 })
>
>
> db.mycol.save({_id:2, name:’newrecord’})
WriteResult({ “nMatched” : 0, “nUpserted” : 1, “nModified” : 0, “_id” : 2 })
>
> db.mycol.save({_id:2, name:’newrecord’})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 0 })
>
> db.mycol.save({_id:2, name:’newrecord’})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 0 })
>
> db.mycol.save({_id:2, name:’updated record‘})
WriteResult({ “nMatched” : 1, “nUpserted” : 0, “nModified” : 1 })
>
>
> db.mycol.insert({_id:2, name:’updated record’})
WriteResult({
“nInserted” : 0,
“writeError” : {
“code” : 11000,
“errmsg” : “E11000 duplicate key error collection: dbversity.mycol index: _id_ dup key: { : 2.0 }”
}
})
>
>
Let us consider the two cases here for save in a pictorial representation :-
1) Having _id in doc.
2) Not having _id in doc.
Save ()
/ \
/ \
Having _id Not Having _id
->In this case save will do -> It will do normal insertion
upsert to insert.Now in this case as insert() do.
what that means, it means
take the document and replace
the complete document having same
_id.
Let us consider the two cases here for insert:-
1) Having _id of doc in collection.
2) Not having _id of doc in collection.
Insert()
/ \
/ \
Doc Having _id in collection Doc Not Having _id
-> E11000 duplicate key ->Insert a new doc inside the collection.
error index:
Save vs Update :
update modifies an existing document matched with your query params. If there is no such matching document, that’s when upsert comes in picture.
upsert : false : Nothing happens when no such document exist
upsert : true : New doc gets created with contents equal to query params and update params
save : Doesn’t allow any query-params. if _id exists and there is a matching doc with the same _id, it replaces it. When no _id specified/no matching document, it inserts the document as a new one.
Save function :
> t.save
function (obj, opts) {
if (obj == null)
throw Error(“can’t save a null”);
if (typeof(obj) == “number” || typeof(obj) == “string”)
throw Error(“can’t save a number or string”);
if (typeof(obj._id) == “undefined”) {
obj._id = new ObjectId();
return this.insert(obj, opts);
} else {
return this.update({_id: obj._id}, obj, Object.merge({upsert: true}, opts));
}
}
>
Insert Function :
> t.insert
function (obj, options) {
if (!obj)
throw Error(“no object passed to insert!”);
var flags = 0;
var wc = undefined;
var allowDottedFields = false;
if (options === undefined) {
// do nothing
} else if (typeof(options) == ‘object’) {
if (options.ordered === undefined) {
// do nothing, like above
} else {
flags = options.ordered ? 0 : 1;
}
if (options.writeConcern)
wc = options.writeConcern;
if (options.allowdotted)
allowDottedFields = true;
} else {
flags = options;
}
// 1 = continueOnError, which is synonymous with unordered in the write commands/bulk-api
var ordered = ((flags & 1) == 0);
if (!wc)
wc = this.getWriteConcern();
var result = undefined;
var startTime =
(typeof(_verboseShell) === ‘undefined’ || !_verboseShell) ? 0 : new Date().getTime();
if (this.getMongo().writeMode() != “legacy”) {
// Bit 1 of option flag is continueOnError. Bit 0 (stop on error) is the default.
var bulk = ordered ? this.initializeOrderedBulkOp() : this.initializeUnorderedBulkOp();
var isMultiInsert = Array.isArray(obj);
if (isMultiInsert) {
obj.forEach(function(doc) {
bulk.insert(doc);
});
} else {
bulk.insert(obj);
}
try {
result = bulk.execute(wc);
if (!isMultiInsert)
result = result.toSingleResult();
} catch (ex) {
if (ex instanceof BulkWriteError) {
result = isMultiInsert ? ex.toResult() : ex.toSingleResult();
} else if (ex instanceof WriteCommandError) {
result = ex;
} else {
// Other exceptions rethrown as-is.
throw ex;
}
}
} else {
if (typeof(obj._id) == “undefined” && !Array.isArray(obj)) {
var tmp = obj; // don’t want to modify input
obj = {_id: new ObjectId()};
for (var key in tmp) {
obj[key] = tmp[key];
}
}
this.getMongo().insert(this._fullName, obj, flags);
// enforce write concern, if required
if (wc)
result = this.runCommand(“getLastError”, wc instanceof WriteConcern ? wc.toJSON() : wc);
}
this._lastID = obj._id;
this._printExtraInfo(“Inserted”, startTime);
return result;
}
>
Update Function :
> t.update function (query, obj, upsert, multi) { var parsed = this._parseUpdate(query, obj, upsert, multi); var query = parsed.query; var obj = parsed.obj; var upsert = parsed.upsert; var multi = parsed.multi; var wc = parsed.wc; var collation = parsed.collation; var arrayFilters = parsed.arrayFilters; var result = undefined; var startTime = (typeof(_verboseShell) === 'undefined' || !_verboseShell) ? 0 : new Date().getTime(); if (this.getMongo().writeMode() != "legacy") { var bulk = this.initializeOrderedBulkOp(); var updateOp = bulk.find(query); if (upsert) { updateOp = updateOp.upsert(); } if (collation) { updateOp.collation(collation); } if (arrayFilters) { updateOp.arrayFilters(arrayFilters); } if (multi) { updateOp.update(obj); } else { updateOp.updateOne(obj); } try { result = bulk.execute(wc).toSingleResult(); } catch (ex) { if (ex instanceof BulkWriteError) { result = ex.toSingleResult(); } else if (ex instanceof WriteCommandError) { result = ex; } else { // Other exceptions thrown throw ex; } } } else { if (collation) { throw new Error("collation requires use of write commands"); } if (arrayFilters) { throw new Error("arrayFilters requires use of write commands"); } this.getMongo().update(this._fullName, query, obj, upsert, multi); // Enforce write concern, if required if (wc) { result = this.runCommand("getLastError", wc instanceof WriteConcern ? wc.toJSON() : wc); } } this._printExtraInfo("Updated", startTime); return result; } >
Comments are closed, but trackbacks and pingbacks are open.