Append item to MongoDB document array in PyMongo without re-insertion
Solution 1
You don't need to use to retrieve the document first just use the .update
method with the $push
operator.
def update_tags(ref, new_tag):
coll.update({'ref': ref}, {'$push': {'tags': new_tag}})
Since update is deprecated you should use the find_one_and_update
or the update_one
method if you are using pymongo 2.9 or newer
Solution 2
Just to add to @ssytvane answer,and to answer @Guarav: you can add "upsert = True" if it does not exist:
def update_tags(ref, new_tag):
coll.update({'ref': ref}, {'$push': {'tags': new_tag}}, upsert = True)
or
def update_tags(ref, new_tag):
coll.update_one({'ref': ref}, {'$push': {'tags': new_tag}}, upsert = True)
Solution 3
You can simply do
1) If you want to append single entry
def update_tags(ref, new_tag):
coll.update({'ref': ref}, {'$push': {'tags': new_tag}})
eg:
{
"_id" : ObjectId("561c199e038e42b10956e3fc"),
"tags" : [ "tag1", "tag2", "tag3" ],
"ref" : "4780"
}
>> update_tags("4780", "tag4")
{'updatedExisting': True, u'nModified': 1, u'ok': 1, u'n': 1}
>> coll.find_one({"ref":"4780"})
{
"_id" : ObjectId("561c199e038e42b10956e3fc"),
"tags" : [ "tag1", "tag2", "tag3" , "tag4" ],
"ref" : "4780"
}
2) If you want to append multiple entries
def update_tags(ref, new_tag):
coll.update({'ref': ref}, {'$pushAll': {'tags': new_tag}}) #type of new_tag is list
eg:
{
"_id" : ObjectId("561c199e038e42b10956e3fc"),
"tags" : [ "tag1", "tag2", "tag3" ],
"ref" : "4780"
}
>> update_tags("4780", ["tag5", "tag6", "tag7"])
{'updatedExisting': True, u'nModified': 1, u'ok': 1, u'n': 1}
>> coll.find_one({"ref":"4780"})
{
"_id" : ObjectId("561c199e038e42b10956e3fc"),
"tags" : [ "tag1", "tag2", "tag3" , "tag4" , "tag5", "tag6", "tag7" ],
"ref" : "4780"
}
Note: If the key is not already present, then mongo will create new key.
Solution 4
There had been some good answers that are correct but in my opinion writing update_tags this way is better and more usable:
def update_tags(ref, *args):
coll.update_one(ref, {'$push': {'tags': {'$each': args}}})
this way you can do both appending one tag or appending many tags:
>> update_tags(ref, 'tag5')
>> update_tags(ref, 'tag5', 'tag6')
>> list_of_new_tags = do_something_that_returns_list_of_tags()
>> update_tags(ref, *list_of_new_tags)
Related videos on Youtube
deadbits
Updated on January 08, 2022Comments
-
deadbits over 2 years
I am using MongoDB as the back-end database for Python web application (PyMongo + Bottle). Users can upload files and optionally 'tag' these files during upload. The tags are stored as a list within the document, per below:
{ "_id" : ObjectId("561c199e038e42b10956e3fc"), "tags" : [ "tag1", "tag2", "tag3" ], "ref" : "4780" }
I am trying to allow users to append new tags to any document. I came up with something like this:
def update_tags(ref, new_tag) # fetch desired document by ref key as dict document = dict(coll.find_one({'ref': ref})) # append new tag document['tags'].append(new_tag) # re-insert the document back into mongo coll.update(document)
(fyi;
ref
key is always unique. this could easily be_id
as well.) It seems like there should be a way to just update the 'tags' value directly without pulling back the entire document and re-inserting. Am I missing something here?Any thoughts are greatly appreciated :)
-
langlauf.io over 7 yearsWhat is the difference between the two? Just the return value (the document vs an UpdateResult object) ? When do you use one or the other?
-
Gaurav Ojha about 7 yearsWhat happens if 'tags' field doesn't exist?
-
styvane over 6 yearsIf
tags
field doesn't exist, it is created. @GauravOjha -
Rajiv Sharma over 5 yearspymongo.errors.WriteError: Unknown modifier: $pushAll
-
Navi almost 4 yearswhat is ref here?
-
Navi almost 4 yearsWill it delete the old record?
-
Navi almost 4 yearsmust be an array but is of type object in document this error pops up
-
A.N.Tanvir almost 4 years
$pushAll
won't work for appending multiple values to an array. Use$push
with the$each
modifier to append multiple values to the array field.{'$push': {'tags': { '$each': new_tags_array}}}
-
Zaraki Kenpachi over 2 yearsupsert (optional): When True, inserts a new document if no document matches the query. Defaults to False. api.mongodb.com/python/2.9/api/pymongo/…
-
Belly Buster over 2 yearsDon't add questions as an answer; start a new question of you're own.
-
Flair over 2 yearsIf you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review
-
Jason117 over 2 yearswhat happens if the new_tag already exits?
-
Rylan Schaeffer about 2 yearsWhen I try appending a dictionary to a list, I get
{TypeError}unhashable type: 'dict'
. Why is PyMongo trying to hash the dictionary, and how do I append a dictionary to the list? -
ray almost 2 yearsIf you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review