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

dea*_*its 19 python mongodb pymongo mongodb-query

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

{
    "_id" : ObjectId("561c199e038e42b10956e3fc"),
    "tags" : [ "tag1", "tag2", "tag3" ],
    "ref" : "4780"
}
Run Code Online (Sandbox Code Playgroud)

我试图允许用户将新标签附加到任何文档.我提出了这样的事情:

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)
Run Code Online (Sandbox Code Playgroud)

(fyi; refkey总是唯一的.这也很容易_id.)似乎应该有一种方法可以直接更新'tags'值而不需要拉回整个文档并重新插入.我在这里错过了什么吗?

任何想法都非常感谢:)

sty*_*ane 24

您不需要首先使用该.update方法与$push操作员一起使用来检索文档.

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$push': {'tags': new_tag}})
Run Code Online (Sandbox Code Playgroud)

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

  • 如果'tags'字段不存在会怎样? (4认同)
  • 如果“tags”字段不存在,则会创建它。@GauravOjha (3认同)
  • 两者有什么区别?只是返回值(文档与 UpdateResult 对象)?你什么时候使用其中一个? (2认同)

小智 11

你可以简单地做

1) 如果您想追加单个条目

def update_tags(ref, new_tag):
    coll.update({'ref': ref}, {'$push': {'tags': new_tag}})
Run Code Online (Sandbox Code Playgroud)

例如:

{
    "_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"
}
Run Code Online (Sandbox Code Playgroud)

2) 如果您想追加多个条目

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

例如:

{
    "_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"
}
Run Code Online (Sandbox Code Playgroud)

注意:如果密钥尚不存在,那么 mongo 将创建新密钥。


Kil*_*a.A 5

只是为了添加到@ssytvane 答案,并回答@Guarav:如果它不存在,您可以添加“upsert = True”:

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

或者

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


Arm*_*nMz 5

有一些正确的好答案,但在我看来,以这种方式编写 update_tags 更好、更有用:

def update_tags(ref, *args):
    coll.update_one(ref, {'$push': {'tags': {'$each': args}}})
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以附加一个标签或附加多个标签:

>> update_tags(ref, 'tag5')
Run Code Online (Sandbox Code Playgroud)
>> update_tags(ref, 'tag5', 'tag6')
Run Code Online (Sandbox Code Playgroud)
>> list_of_new_tags = do_something_that_returns_list_of_tags()
>> update_tags(ref, *list_of_new_tags)
Run Code Online (Sandbox Code Playgroud)