What's the difference between insert(), insertOne(), and insertMany() method? - mongodb

What's the difference between insert(), insertOne(), and insertMany() methods on MongoDB. In what situation should I use each one?
I read the docs, but it's not clear when use each one.

What's the difference between insert(), insertOne() and insertMany() methods on MongoDB
db.collection.insert() as mentioned in the documentation inserts a document or documents into a collection and returns
a WriteResult object for single inserts and a BulkWriteResult object for bulk inserts.
> var d = db.collection.insert({"b": 3})
> d
WriteResult({ "nInserted" : 1 })
> var d2 = db.collection.insert([{"b": 3}, {'c': 4}])
> d2
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 2,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})
db.collection.insertOne() as mentioned in the documentation inserts a document into a collection and returns a document which look like this:
> var document = db.collection.insertOne({"a": 3})
> document
{
"acknowledged" : true,
"insertedId" : ObjectId("571a218011a82a1d94c02333")
}
db.collection.insertMany() inserts multiple documents into a collection and returns a document that looks like this:
> var res = db.collection.insertMany([{"b": 3}, {'c': 4}])
> res
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("571a22a911a82a1d94c02337"),
ObjectId("571a22a911a82a1d94c02338")
]
}
In what situation should I use each one?
The insert() method is deprecated in major driver so you should use the
the .insertOne() method whenever you want to insert a single document into your collection and the .insertMany when you want to insert multiple documents into your collection. Of course this is not mentioned in the documentation but the fact is that nobody really writes an application in the shell. The same thing applies to updateOne, updateMany, deleteOne, deleteMany, findOneAndDelete, findOneAndUpdate and findOneAndReplace. See Write Operations Overview.

db.collection.insert():
It allows you to insert One or more documents in the collection. Syntax:
Single insert: db.collection.insert({<document>});
Multiple insert:
db.collection.insert([
, , ...
]);
Returns a WriteResult object: WriteResult({ "nInserted" : 1 });
db.collection.insertOne():
It allows you to insert exactly 1 document in the collection. Its syntax is the same as that of single insert in insert().
Returns the following document:
{
"acknowledged" : true,
"insertedId" : ObjectId("56fc40f9d735c28df206d078")
}
db.collection.insertMany():
It allows you to insert an array of documents in the collection. Syntax:
db.collection.insertMany(
{ [ <document 1> , <document 2>, ... ] });
Returns the following document:
{
"acknowledged" : true,
"insertedIds" : [
ObjectId("562a94d381cb9f1cd6eb0e1a"),
ObjectId("562a94d381cb9f1cd6eb0e1b"),
ObjectId("562a94d381cb9f1cd6eb0e1c")
]
}
All three of these also allow you to define a custom writeConcern and also create a collection if it doesn't exist.

There is also a difference in error handling, check here. The insert command returns a document in both success and error cases. But the insertOne and insertMany commands throws exceptions. Exceptions are easier to handle in code, than evaluating the returned document to figure out errors. Probably the reason why they are deprecated in the drivers as mentioned in sstyvane's answer.

Also to add to another answer, if the user calls the InsertOne function instead of InsertMany and passes the array of documents to insert. then it is also allowed and will not give any errors. It will create only one document which will have an array of these documents. so be careful.

If the collection does not exist, then the insertOne() method creates the collection. If you input the same data again, mongod will create another unique id to avoid duplication.

Related

pymongo update creates a new record without upserting

I have an issue where I do an update on a document, however, the update creates a new document and I'm not upserting in my update.
This is my testing code.
I do a find to see if the document exists by checking if "lastseen" doesn't exist:
result = DATA_Collection.find({"sessionID":"12345","lastseen":{"$exists":False}})
if result.count() == 1:
DATA_Collection.update({"sessionID":"12345"},{"$set":{"lastseen":"2021-05-07"}})
When I do an aggregate check to find duplicates I get a few, one example below.
> db.DATA_Collection.find({ "sessionID" : "237a5fb8" })
{ "_id" : ObjectId("60bdf7b05c961b4d27d33bde"), "sessionID" : "237a5fb8", "firstseen" : ISODate("1970-01-19T20:51:09Z"), "lastseen" : ISODate("2021-06-07T12:34:20Z") }
{ "_id" : ObjectId("60bdf7fa7d35ea0f046a2514"), "sessionID" : "237a5fb8", "firstseen" : ISODate("1970-01-19T20:51:09Z") }
I remove all the records in the collection and rerun the script, the same happens again.
Any advice will be much appreciated.
Firstly your pymongo commands are deprecated; use update_one() or update_many() instead of update(); count_documents() instead of count().
Secondly double check you are referencing the same collections as you mention DATA_Collection and VPN_DATA;
How are you defining a "duplicate"? Unless you create a unique index on the field(s), the records won't be duplicates as they have different _id fields.
You need something like:
record = db.VPN_DATA.find_one({'sessionID': '12345', 'lastseen': {'$exists': False}})
if record is not None:
db.VPN_DATA.update_one({'_id': record.get('_id')}, {'$set': {'lastseen': '2021-05-07'}})

Using upsert with the updateOne() method to perform an update operation

I’m using upsert with the updateOne() method as bellow to perform an update.
db.practice.updateOne(
{“title”:“Night Life”},
{$set: detail},
{upsert: true}
)
My query returns the following:
{
"acknowledged" : true,
"matchedCount" : 0,
"modifiedCount" : 0,
"upsertedId" : ObjectId("5f8884fed29ded706c3c6737")
}
Below is the detail variable:
let detail = {
“title” : “Night Life”,
“year” : 2021,
“rated” : “PG-13”,
“released” : 2021,
“runtime” : 60,
“countries” : [
“USA”,
“UK”
],
“genres” : [
“comedy”,
“drama”
],
“director” : “Alpha Ly”,
“actors” : [
“Alpha Ly”,
“Kris Dasha”,
“Hope Grace”
]
}
When I check my collection in Compass, I don’t see the document with the ObjectId("5f8884fed29ded706c3c6737
However, when I run the following command db.practice.find({"director": "Alpha Ly"}).pretty(),
it returns the entry I've looking for in Compass.
NB: the number of documents in my collection is still the same as created.
What seems to be the problem here. Why Compass is not displaying the entry?
It seems like I was not using the correct database.
In order to execute the command, I was supposed to use the use command followed by the name of my database to switch to my database. Since I didn't, the update query created another collection and inserted the document there. Therefore, I couldn't find it in my database.
Thanks

remove needs a query at src/mongo/shell/collection.js

Getting this error when I run db.messages.remove(). "remove needs a query at src/mongo/shell/collection.js". any suggestions to resolve this error?
As the message says you need to provide a query, but it can be an empty one (if you want to remove all documents):
db.messages.remove({})
EDIT: I would like emphasize the comment made by Stennie:
Note: if you actually want to remove all documents in a collection it is faster to a do a collection.drop(). The remove() operation will delete documents individually & update indexes as the documents are deleted; a drop() will immediately delete all documents & indexes for the collection.
If you are trying to drop the collection messages, then you need to execute db.messages.drop().
Otherwise, the command db.messages.remove() is used to delete a particular document and therefore you need to write a query to allow MongoDB engine to know which document needs to be gotten rid of. For ex. db.messages.remove({_id : }).
The lack of {_id : } is causing the error that remove needs a query....
Run:
db.collectionname.remove({});
result :
WriteResult({ "nRemoved" : 7 })
Remove all collections from MongoDB database, use below Syntax:
db.getCollectionNames().forEach(
function(collection_name){
print('CollectionName: '+ collection_name +', '+ db[collection_name].remove({})
)
});
Output:
CollectionName: Document_CODE, WriteResult({ "nRemoved" : 20 })
CollectionName: Document_DATA, WriteResult({ "nRemoved" : 10 })
CollectionName: Document_NAME, WriteResult({ "nRemoved" : 10 })
CollectionName: Document_COLLE, WriteResult({ "nRemoved" : 1 })

mongodb mapreduce doesn't return right in a sharded cluster

very interesting, mapreduce works fine in a single instance, but not on a sharded collection. as below, you may see that i got a collection and write a simple map-reduce
function,
mongos> db.tweets.findOne()
{
"_id" : ObjectId("5359771dbfe1a02a8cf1c906"),
"geometry" : {
"type" : "Point",
"coordinates" : [
131.71778292855996,
0.21856835860911106
]
},
"type" : "Feature",
"properties" : {
"isflu" : 1,
"cell_id" : 60079,
"user_id" : 35,
"time" : ISODate("2014-04-24T15:42:05.048Z")
}
}
mongos> db.tweets.find({"properties.user_id":35}).count()
44247
mongos> map_flow
function () { var key=this.properties.user_id; var value={ "cell_id":1}; emit(key,value); }
mongos> reduce2
function (key,values){ var ros={flows:[]}; values.forEach(function(v){ros.flows.push(v.cell_id);});return ros;}
mongos> db.tweets.mapReduce(map_flow,reduce2, { out:"flows2", sort:{"properties.user_id":1,"properties.time":1} })
but the results are not what i want
mongos> db.flows2.find({"_id":35})
{ "_id" : 35, "value" : { "flows" : [ null, null, null ] } }
I got lots of null and interesting all have three ones.
mongodb mapreduce seems not right on sharded collection?
The number one rule of MapReduce is:
thou shall emit the value of the same type as reduce function returneth
You broke this rule, so your MapReduce only works for small collection where reduce is only called once for each key (that's the second rule of MapReduce - reduce function may be called zero, once or many times).
Your map function emits exactly this value {cell_id:1} for each document.
How does your reduce function use this value? Well, you return a value which is a document with an array, into which you push the cell_id value. This is strange already, because that value was 1, so I'm not sure why you wouldn't just emit 1 (if you wanted to count).
But look what happens when multiple shards push a bunch of 1's into this flows array (whether it's what you intended, that's what your code is doing) and now reduce is called on several already reduced values:
reduce(key, [ {flows:[1,1,1,1]},{flows:[1,1,1,1,1,1,1,1,1]}, etc ] )
Your reduce function now tries to take each member of the values array (which is a document with a single field flows) and you push v.cell_id to your flows array. There is no cell_id field here, so of course you end up with null. And three nulls could be because you have three shards?
I would recommend that you articulate to yourself what exactly you are trying to aggregate in this code, and then rewrite your map and your reduce to comply with the rules that mapReduce in MongoDB expects your code to follow.

Add new field to all documents in a nested array

I have a database of person documents. Each has a field named photos, which is an array of photo documents. I would like to add a new 'reviewed' flag to each of the photo documents and initialize it to false.
This is the query I am trying to use:
db.person.update({ "_id" : { $exists : true } }, {$set : {photos.reviewed : false} }, false, true)
However I get the following error:
SyntaxError: missing : after property id (shell):1
Is this possible, and if so, what am I doing wrong in my update?
Here is a full example of the 'person' document:
{
"_class" : "com.foo.Person",
"_id" : "2894",
"name" : "Pixel Spacebag",
"photos" : [
{
"_id" : null,
"thumbUrl" : "http://site.com/a_s.jpg",
"fullUrl" : "http://site.com/a.jpg"
},
{
"_id" : null,
"thumbUrl" : "http://site.com/b_s.jpg",
"fullUrl" : "http://site.com/b.jpg"
}]
}
Bonus karma for anyone who can tell me a cleaner why to update "all documents" without using the query { "_id" : { $exists : true } }
For those who are still looking for the answer it is possible with MongoDB 3.6 with the all positional operator $[] see the docs:
db.getCollection('person').update(
{},
{ $set: { "photos.$[].reviewed" : false } },
{ multi: true}
)
Is this possible, and if so, what am I doing wrong in my update?
No. In general MongoDB is only good at doing updates on top-level objects.
The exception here is the $ positional operator. From the docs: Use this to find an array member and then manipulate it.
However, in your case you want to modify all members in an array. So that is not what you need.
Bonus karma for anyone who can tell me a cleaner why to update "all documents"
Try db.coll.update(query, update, false, true), this will issue a "multi" update. That last true is what makes it a multi.
Is this possible,
You have two options here:
Write a for loop to perform the update. It will basically be a nested for loop, one to loop through the data, the other to loop through the sub-array. If you have a lot of data, you will want to write this is your driver of choice (and possibly multi-thread it).
Write your code to handle reviewed as nullable. Write the data such that if it comes across a photo with reviewed undefined then it must be false. Then you can set the field appropriately and commit it back to the DB.
Method #2 is something you should get used to. As your data grows and you add fields, it becomes difficult to "back-port" all of the old data. This is similar to the problem of issuing a schema change in SQL when you have 1B items in the DB.
Instead just make your code resistant against the null and learn to treat it as a default.
Again though, this is still not the solution you seek.
You can do this
(null, {$set : {"photos.reviewed" : false} }, false, true)
The first parameter is null : no specification = any item in the collection.
"photos.reviewed" should be declared as string to update subfield.
You can do like this:
db.person.update({}, $set:{name.surname:null}, false, true);
Old topic now, but this just worked fine with Mongo 3.0.6:
db.users.update({ _id: ObjectId("55e8969119cee85d216211fb") },
{ $set: {"settings.pieces": "merida"} })
In my case user entity looks like
{ _id: 32, name: "foo", ..., settings: { ..., pieces: "merida", ...} }