WriteResult mongoDB for update operation - mongodb

I want to insert records and updating attributes using update and get the status of the update. I used getN () method WriteResult. The problem is that if the attributes exist it always returns me one while I wish that I returns 0. thank you
here is my update request :
db.friends.update( {adv: "man2ist", "list.id" : {$ne : "5" }} , {$addToSet : {"list" : {'id' : "5" , 'value' : 100 }} } ,false , true);

The n value in a WriteResult provides the number of documents that were updated, and it can only be 0 if your update query didn't match any documents and you're not doing an upsert. Your best bet here might be to use findAndModify and make a comparison to the old document.

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'}})

MongoDB get object id by finding on another column value

I am new to querying dbs and especially mongodb.If I run :
db.<customers>.find({"contact_name: Anny Hatte"})
I get:
{
"_id" : ObjectId("55f7076079cebe83d0b3cffd"),
"company_name" : "Gap",
"contact_name" : "Anny Hatte",
"email" : "ahatte#gmail.com"
}
I wish to get the value of the "_id" attribute from this query result. How do I achieve that?
Similarly, if I have another collection, named items, with the following data:
{
"_id" : ObjectId("55f7076079cebe83d0b3d009"),
"_customer" : ObjectId("55f7076079cebe83d0b3cfda"),
"school" : "St. Patrick's"
}
Here, the "_customer" field is the "_id" of the customer collection (the previous collection). I wish to get the "_id", the "_customer" and the "school" field values for the record where "_customer" of items-collection equals "_id" of customers-collection.
How do I go about this?
I wish to get the value of the "_id" attribute from this query result.
How do I achieve that?
The find() method returns a cursor to the results, which you can iterate and retrieve the documents in the result set. You can do this using forEach().
var cursor = db.customers.find({"contact_name: Anny Hatte"});
cursor.forEach(function(customer){
//access all the attributes of the document here
var id = customer._id;
})
You could make use of the aggregation pipeline's $lookup stage that has been introduced as part of 3.2, to look up and fetch the matching rows in some other related collection.
db.customers.aggregate([
{$match:{"contact_name":"Anny Hatte"}},
{$lookup:{
"from":"items",
"localField":"_id",
"foreignField":"_customer",
"as":"items"
}}
])
In case you are using a previous version of mongodb where the stage is not supported, then, you would need to fire an extra query to lookup the items collection, for each customer.
db.customers.find(
{"contact_name":"Anny Hatte"}).map(function(customer){
customer["items"] = [];
db.items.find({"_customer":customer._id}).forEach(function(item){
customer.items.push(item);
})
return customer;
})

Get position of selected document in collection [mongoDB]

How to get position (index) of selected document in mongo collection?
E.g.
this document: db.myCollection.find({"id":12345})
has index 3 in myCollection
myCollection:
id: 12340, name: 'G'
id: 12343, name: 'V'
id: 12345, name: 'A'
id: 12348, name: 'N'
If your requirement is to find the position of the document irrespective of any order, that is not
possible as MongoDb does not store the documents in specific order.
However,if you want to know the index based on some field, say _id , you can use this method.
If you are strictly following auto increments in your _id field. You can count all the documents
that have value less than that _id, say n , then n + 1 would be index of the document based on _id.
n = db.myCollection.find({"id": { "$lt" : 12345}}).count() ;
This would also be valid if documents are deleted from the collection.
As far as I know, there is no single command to do this, and this is impossible in general case (see Derick's answer). However, using count() for a query done on an ordered id value field seems to work. Warning: this assumes that there is a reliably ordered field, which is difficult to achieve in a concurrent writer case. In this example _id is used, however this will only work with a single writer case.:
MongoDB shell version: 2.0.1
connecting to: test
> use so_test
switched to db so_test
> db.example.insert({name: 'A'})
> db.example.insert({name: 'B'})
> db.example.insert({name: 'C'})
> db.example.insert({name: 'D'})
> db.example.insert({name: 'E'})
> db.example.insert({name: 'F'})
> db.example.find()
{ "_id" : ObjectId("4fc5f040fb359c680edf1a7b"), "name" : "A" }
{ "_id" : ObjectId("4fc5f046fb359c680edf1a7c"), "name" : "B" }
{ "_id" : ObjectId("4fc5f04afb359c680edf1a7d"), "name" : "C" }
{ "_id" : ObjectId("4fc5f04dfb359c680edf1a7e"), "name" : "D" }
{ "_id" : ObjectId("4fc5f050fb359c680edf1a7f"), "name" : "E" }
{ "_id" : ObjectId("4fc5f053fb359c680edf1a80"), "name" : "F" }
> db.example.find({_id: ObjectId("4fc5f050fb359c680edf1a7f")})
{ "_id" : ObjectId("4fc5f050fb359c680edf1a7f"), "name" : "E" }
> db.example.find({_id: {$lte: ObjectId("4fc5f050fb359c680edf1a7f")}}).count()
5
>
This should also be fairly fast if the queried field is indexed. The example is in mongo shell, but count() should be available in all driver libs as well.
This might be very slow but straightforward method. Here you can pass as usual query. Just I am looping all the documents and checking if condition to match the record. Here I am checking with _id field. You can use any other single field or multiple fields to check it.
var docIndex = 0;
db.url_list.find({},{"_id":1}).forEach(function(doc){
docIndex++;
if("5801ed58a8242ba30e8b46fa"==doc["_id"]){
print('document position is...' + docIndex);
return false;
}
});
There is no way that MongoDB can return this as it does not keep documents in order in the database, just like MySQL f.e. doesn't name row numbers.
The ObjectID trick from jhonkola will only work if only one client creates new elements, as the ObjectIDs are generated on the client side, with the first part being a timestamp. There is no guaranteed order if different clients talk to the same server. Still, I would not rely on this.
I also don't quite understand what you are trying to do though, so perhaps mention that in your question? I can then update the answer.
Restructure your collection to include the position of any entry i.e {'id': 12340, 'name': 'G', 'position': 1} then when searching the database collection(myCollection) using the desired position as a query
The queries I use that return the entire collection all use sort to get a reproducible order, find.sort.forEach works with the script above to get the correct index.

How to replace an object in a MongoDB record?

How to replace third_id in this record (only one document needs to be updated)?
> db.collection.find( {"_id" : ObjectId("4f90cf0cd4bea011930001a3"), "first_id": ObjectId("4edf056800126757c000000f")}) { "second_id" : ObjectId("4f355e430012671d77000ec0"), "third_id" : ObjectId("4edf056800126757c000000f"), "note" : "blah-blah"}
Like this?
db.collection.update( { {"_id" : ObjectId("4f90cf0cd4bea011930001a3"), "third_id" : ObjectId("5edf056800126757c000000f")}, , true )
Tutorial says:
db.collection.update( criteria, objNew, upsert, multi )
Arguments:
criteria - query which selects the record to update;
objNew - updated object or $ operators (e.g., $inc) which manipulate the object
upsert - if this should be an "upsert" operation; that is, if the record(s) do not exist,
insert one. Upsert only inserts a single document.
multi - indicates if all documents matching criteria should be updated rather than just one. Can be useful with the $ operators below.
Since you only want to update a single document and you aren't trying to do an upsert and you don't want to replace the whole document but just one field, you can do:
db.collection.update( { {"_id" : ObjectId("4f90cf0cd4bea011930001a3"),
{ $set : {"third_id" : ObjectId("5edf056800126757c000000f") } } )

Add new field to every document in a MongoDB collection

How can I add a new field to every document in an existent collection?
I know how to update an existing document's field but not how to add a new field to every document in a collection. How can I do this in the mongo shell?
Same as the updating existing collection field, $set will add a new fields if the specified field does not exist.
Check out this example:
> db.foo.find()
> db.foo.insert({"test":"a"})
> db.foo.find()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "test" : "a" }
> item = db.foo.findOne()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "test" : "a" }
> db.foo.update({"_id" :ObjectId("4e93037bbf6f1dd3a0a9541a") },{$set : {"new_field":1}})
> db.foo.find()
{ "_id" : ObjectId("4e93037bbf6f1dd3a0a9541a"), "new_field" : 1, "test" : "a" }
EDIT:
In case you want to add a new_field to all your collection, you have to use empty selector, and set multi flag to true (last param) to update all the documents
db.your_collection.update(
{},
{ $set: {"new_field": 1} },
false,
true
)
EDIT:
In the above example last 2 fields false, true specifies the upsert and multi flags.
Upsert: If set to true, creates a new document when no document matches the query criteria.
Multi: If set to true, updates multiple documents that meet the query criteria. If set to false, updates one document.
This is for Mongo versions prior to 2.2. For latest versions the query is changed a bit
db.your_collection.update({},
{$set : {"new_field":1}},
{upsert:false,
multi:true})
Since MongoDB version 3.2 you can use updateMany():
> db.yourCollection.updateMany({}, {$set:{"someField": "someValue"}})
To clarify, the syntax is as follows for MongoDB version 4.0.x:
db.collection.update({},{$set: {"new_field*":1}},false,true)
Here is a working example adding a published field to the articles collection and setting the field's value to true:
db.articles.update({},{$set: {"published":true}},false,true)
db.collection.updateMany({}, {$set: {"fieldName": ""}})
updateMany requires a matching condition for each document, since we are passing {} it is always true. And the second argument uses $set operator to add the required field in each document.
Pymongo 3.9+
update() is now deprecated and you should use replace_one(), update_one(), or update_many() instead.
In my case I used update_many() and it solved my issue:
db.your_collection.update_many({}, {"$set": {"new_field": "value"}}, upsert=False, array_filters=None)
if you are using mongoose try this,after mongoose connection
async ()=> await Mongoose.model("collectionName").updateMany({}, {$set: {newField: value}})
The answers above does't cover this scenario. I was looking for the similar query but want to add fields to few documents based on condition.
So, we can use first variable of updateMany to update fields only in few documents.
Example: I want to add a nullable field isDeprecated? to all those Users whose userType is Employer and has country "AAA".
db.users.updateMany({"userType": "Employer", "country": "AAA"}, {"$set": { "isDeprecated?": true }})
This answer will be helpful in those scenarios as well, where we have to find the collection and then update. This can we done in single query like mentioned.