Append item to MongoDB document array in PyMongo without re-insertion
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 :)
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.