MongoDB update object rather than insert a new one - python

Using collection.insert_one(json_dict)inserts a new collection
Can I do collection.insert_one() on an already existing object so it then updates.
My object will look something like:
"_id": 1,
"name": "Bob"
"Age": "57"
Then under "Age" I want to add "Location": "New York', how'd I do that using PyMongo

I you want to add new field to existing document, you need to update it.
There is a function collection.update_one(query, new_values). First argument is query to match existing document and second argument is update document, which will contain update operation. In your case, it would be $set. Read more about update_one here. So, final operation will look like this.
collection.update_one({"_id": 1}, {"$set": {"Location": "New York"}})
It will find document with _id 1 and set Location field or update it if already exists.

You can use the update method with upsert: true to achieve this.
Normally, update changes an existing document. But with upsert: true - if no matching document is found for the update, a new document is created.
Docs: https://docs.mongodb.com/manual/reference/method/db.collection.update/#update-upsert

Related

Pymongo: update document only if value of a field matches a provided value

Is it possible to update a document based on the condition that the value of a field in that document matches a value that I provide?
I can easily do this in two steps but was wondering if there was a way to do it in a single call to MongoAtlas.
It is a single step execution. You don't need two steps.
Reference
And Python implementation is same syntax as plain queries.
db.collection.update_one({
filter condition goes here
},{
'$set': {
update fields goes here
}
}, upsert=False) //Options

insert new field in mongodb database

I'm a beginner in mongodb and pymongo and I'm working on a project where I have a students mongodb collection . What I want is to add a new field and specifically an adrress of a student to each element in my collection (the field is obviously added everywhere as null and will be filled by me later).
However when I try using this specific example to add a new field I get a the following syntax error:
client = MongoClient('mongodb://localhost:27017/') #connect to local mongodb
db = client['InfoSys'] #choose infosys database
students = db['Students']
students.update( { $set : {"address":1} } ) #set address field to every column (error happens here)
How can I fix this error?
You are using the update operation in wrong manner. Update operation is having the following syntax:
db.collection.update(
<query>,
<update>,
<options>
)
The main parameter <query> is not at all mentioned. It has to be at least empty like {}, In your case the following query will work:
db.students.update(
{}, // To update the all the documents.
{$set : {"address": 1}}, // Update the address field.
{multi: true} // To do multiple updates, otherwise Mongo will just update the first matching document.
)
So, in python, you can use update_many to achieve this. So, it will be like:
students.update_many(
{},
{"$set" : {"address": 1}}
)
You can read more about this operation here.
The previous answer here is spot on, but it looks like your question may relate more to PyMongo and how it manages updates to collections. https://pymongo.readthedocs.io/en/stable/api/pymongo/collection.html
According to the docs, it looks like you may want to use the 'update_many()' function. You will still need to make your query (all documents, in this case) as the first argument, and the second argument is the operation to perform on all records.
client = MongoClient('mongodb://localhost:27017/') #connect to local mongodb
db = client['InfoSys'] #choose infosys database
students = db['Students']
sudents.update_many({}, {$set : {"address":1}})
I solved my problem by iterating through every element in my collection and inserting the address field to each one.
cursor = students.find({})
for student in cursor :
students.update_one(student, {'$set': {'address': '1'}})

$mul after $inc updates in MongoDB in one update

Is it possible to update a single document by passing $inc and $mul operators in a single update document?
For example, I am trying to $mul after $inc in a given document using the following update document:
{
"$inc": {"price": 100},
"$mul": {"price": 10}
}
it raise WriteError: Cannot update 'shaped_high' and 'shaped_high' at the same time
Is there a way to do this or is there something I am missing?
It is possible to have multiple field operators ($inc, $mul, etc) in the same update operation. However, you cannot perform multiple modifications on the same field (of the document), in a single update operation.

Why the mongodb update method creates a new collection with the extension '_keys'?

I used the mongoDB method update to modify existing documents in a collection named annotations. My command, written in a Python script, is:
db['annotations'].update({'_id': annotation['_id']}, {'$set': {'orthologs': orthologs}}, False)
The field orthologs must be modify to contain a new subfield UniProt that is given by the variable named orthologs.
Surprisingly, a new collection was created with the name annotations_keys. It contains only one document : { "_id" : "UniProt", "value" : null }.
Is it normal? If not, what is the problem?
Yes Rafael, I'm sure.
The new created collection is really named 'annotationS'+'_keys' like the initial collection 'annotationS'. In addition, annotation['_id'] comes from a loop that finds in the db each document ('annotation') corresponding to the request:
annotation = db['annotations'].find_one({'class': 'CDS', 'locus_tag': annotated_molecule.name})

Updating a nested mongodb collection using a cursor

I am new to mongodb and am using it to store a nested document. E.g. Each document contains an array of students for each class. I am trying to update the information in each of the array nodes. Is there a better way to do it instead of updating each of the array element one at a time?
Here is my record in the collection -
{
“_id” : “23343” ,
“class” : “Physics”,
“students”: [
{ “id” : “2412” , “name” : "Alice", “mentor” : 0 },
{ “id” : “2413” , “name” : "Bob, “mentor” : 0 },
]
}
There are multiple records like this in the collection.
I have a list of these courses I need to update for each record. For example I get an array of students for the above record to update like this -
{
“_id” : “23343” ,
“class” : “Physics”,
“students”: [
{ “id” : “2412” , “name” : "Alice", “mentor” : "Mark" },
{ “id” : “2413” , “name” : "Bob, “mentor” : "Jackson" },
]
}
What is the best way to update the record?
I am using python. Intuitively,I can do a find() on the collection for the course. I get a cursor for that. I can do a for each in cursor. I believe mongodb updates the whole document on update().
for record in courseCollection.find():
recordId = record['_id']
updatedList = getUpdatedStudentList( record['students'])
updatedRecord = prepareUpdatedRecord(updatedList)
courseCollection.update( {'_id' : recordId}, updateList)
The pymongo documentation site does not talk about the set option in the update function. Unless I use that I believe mongodb updates the whole document.
Also calling update with a query option by passing in the _id seems unnecessary because I just did the query and have a handle to the record. Can I somehow use the cursor to do the update there by not do the query for the update again?
You can use the $ operator with $elemMatch in an update. Let's start by inserting your document:
collection.insert({
"_id": "23343",
"class": "Physics",
"students": [
{"id": "2412", "name": "Alice", "mentor": 0},
{"id": "2413", "name": "Bob", "mentor": 0}]})
Now I'll run two update statements, first adding the mentor "Mark", then "Jackson":
collection.update(
# Query portion.
{"_id": "23343", "students": {"$elemMatch": {"id": "2412"}}},
# Update portion; $ is the position of the matching student.
{"$set": {"students.$.mentor": "Mark"}})
collection.update(
# Query portion.
{"_id": "23343", "students": {"$elemMatch": {"id": "2413"}}},
{"$set": {"students.$.mentor": "Jackson"}})
Each update statement affects just the "mentor" field of one subdocument in the "students" array.
I am not so sure what the question is, exactly. In a nutshell: yes, you'll have to update the 'parent' object and yes, you can use $set or replace the entire document, which would be the default behavior. The difference is mostly a matter of locking, concurrency and ownership which is a bit complex. Here's a little more detail on some of your concerns:
Updating a nested mongodb collection using a cursor
Please note that there are no "nested collections", there are only embedded documents. That's important, because the first class citizen in mongodb is always the actual document itself. For instance, a find() will return documents, not subsets of embedded documents alone. You can do projections, but that's only an output transformation, so to speak.
I can do a find() on the collection for the course. I get a cursor for that.
You get a cursor, but since you're querying on the primary key there can only be a single match (primary keys are unique), i.e. you could use findOne() and you don't need to iterate the single result.
E.g. Each document contains an array of students for each class.
These should usually be references to the students, i.e. there should be a separate students collection because you don't want to lose the student because it was temporarily not assigned to any course.
The pymongo documentation site does not talk about the set option in the update function. Unless I use that I believe mongodb updates the whole document.
That's true. You can do a $set on the students array of a document. That avoids overwriting any other fields, such as class. On the other hand, if somebody else has changed the class while your using was editing the students, do the updates still make sense? Unclear ownership is my primary concern with embedded documents.
Also calling update with a query option by passing in the _id seems unnecessary because I just did the query and have a handle to the record
...but what exactly is a handle to the record? A handle is an immutable, unique and usually short identifier. Just like the id. The _id is the handle. I don't know python, but I guess you could write a method that takes a pointer to a database object and performs an update, knowing that every database object must have a field called _id. But from the database's perspective, a pointer in your code is not a handle, but the id is.

Categories