将项目附加到PyMongo中的MongoDB文档数组,而无需重新插入

时间:2015-10-17 17:06:10

标签: python mongodb mongodb-query pymongo

我使用MongoDB作为Python Web应用程序的后端数据库(PyMongo + Bottle)。用户可以上传文件,并可选择在上传过程中“标记”这些文件。标签存储在文档中的列表中,如下所示:

{
    "_id" : ObjectId("561c199e038e42b10956e3fc"),
    "tags" : [ "tag1", "tag2", "tag3" ],
    "ref" : "4780"
}

我正在尝试允许用户将新标记附加到任何文档。我想出了类似的东西:

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键始终是唯一的。这也很容易_id。) 看起来应该有一种方法可以直接更新'tags'值而不需要撤回整个文档并重新插入。我在这里错过了什么吗?

非常感谢任何想法:)

5 个答案:

答案 0 :(得分:19)

您不需要先使用.update方法与$push运算符一起使用来检索文档。

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$push': {'tags': new_tag}})

由于不推荐使用更新,因此如果您使用的是pymongo 2.9或更新版本,则应使用find_one_and_updateupdate_one方法

答案 1 :(得分:2)

只需添加@ssytvane答案,并回答@Guarav:如果不存在,可以添加“upsert = True”:

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$push': {'tags': new_tag}}, upsert = True)

def update_tags(ref, new_tag):
    coll.update_one({'ref': ref}, {'$push': {'tags': new_tag}}, upsert = True)

答案 2 :(得分:2)

你可以简单地做

1)如果你想附加单一条目

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$push': {'tags': new_tag}})

例如:

{
    "_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)如果你想附加多个条目

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$pushAll': {'tags': new_tag}}) #type of new_tag is list

例如:

{
    "_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"
}

注意:如果密钥尚未存在,则mongo将创建新密钥。

答案 3 :(得分:1)

曾经有一些正确的答案,但是我认为以这种方式编写update_tags更好,更有用:

def update_tags(ref, *args):
    coll.update_one(ref, {'$push': {'tags': {'$each': args}}})

这样,您既可以附加一个标签,也可以附加许多标签:

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

答案 4 :(得分:-1)

您可以使用$push

collection_name.update_one({'ref': ref}, {'$push': {'tags': new_tag}})

您可以在一个查询中更新多个数组

collection_name.update_one({'ref': ref}, {'$push': {'field1': value1, 'filed2': value2}})

值可以按如下方式推送。

{ $push: { <field1>: <value1>, ... } }