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

Posted

技术标签:

【中文标题】将项目附加到 PyMongo 中的 MongoDB 文档数组而不重新插入【英文标题】:Append item to MongoDB document array in PyMongo without re-insertion 【发布时间】:2016-01-16 07:33:44 【问题描述】:

我使用 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)

(仅供参考;ref 密钥始终是唯一的。这也很容易成为 _id。) 似乎应该有一种方法可以直接更新“标签”值,而无需拉回整个文档并重新插入。我在这里遗漏了什么吗?

任何想法都非常感谢:)

【问题讨论】:

【参考方案1】:

在这里添加一点问题。

def create_course(course_name, course_teacher, username):
  db.Accounts.find_one('username':username)['courses'].apppend('name':course_name, 'teacher':course_teacher)

这是尝试将课程添加到仪表板。由于某种原因它失败了,我不知道为什么

【讨论】:

不要添加问题作为答案;开始一个你自己的新问题。 如果您有新问题,请点击 按钮提出问题。如果有助于提供上下文,请包含指向此问题的链接。 - From Review【参考方案2】:

您可以使用$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>, ...  

【讨论】:

【参考方案3】:

已经有一些很好的答案是正确的,但我认为以这种方式编写 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) 如果要追加单个条目

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 将创建新密钥。

【讨论】:

pymongo.errors.WriteError:未知修饰符:$pushAll $pushAll 不适用于将多个值附加到数组。使用 $push$each 修饰符将多个值附加到数组字段。 '$push': 'tags': '$each': new_tags_array【参考方案5】:

只是添加到@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)

【讨论】:

这里的 ref 是什么? upsert(可选):当为 True 时,如果没有文档与查询匹配,则插入一个新文档。默认为假。 api.mongodb.com/python/2.9/api/pymongo/…【参考方案6】:

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

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

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

【讨论】:

两者有什么区别?只是返回值(文档与 UpdateResult 对象)?您什么时候使用其中一种? 如果 'tags' 字段不存在会怎样? 如果tags 字段不存在,则创建它。 @GauravOjha 会删除旧记录吗? 必须是数组,但在文档中属于对象类型,会弹出此错误

以上是关于将项目附加到 PyMongo 中的 MongoDB 文档数组而不重新插入的主要内容,如果未能解决你的问题,请参考以下文章

将 Pymongo 数据从列表附加到 pandas 数据框

使用 pymongo 将数据从 Mysql 迁移到 MongoDB

如何使用 html、pymongo 中的按钮更新 mongodb

如何使用 flask_pymongo 将数据从 mongodb 显示到烧瓶模板?

将 Null 项插入集合 Mongodb (Pymongo)

将日期对象放入 MongoDB,使用 pymongo 查询时返回浮点数