【问题标题】:Python3, MongoDB Insert only if document does not existPython3,MongoDB仅在文档不存在时插入
【发布时间】:2020-07-03 11:40:56
【问题描述】:

我目前有一个字典,其中包含从 API 中提取的数据,其中我为每个数据点提供了它自己的变量(job_id、jobtitle、公司等):

output = {
        'ID': job_id, 
        'Title': jobtitle, 
        'Employer' : company, 
        'Employment type' : emptype, 
        'Fulltime' : tid, 
        'Deadline' : deadline, 
        'Link' : webpage
}

我想添加到我的数据库中,很简单:

db.jobs.insert_one(output)

但这一切都在一个 for 循环中,它将创建 30 个独特的新文档,包括名称、标题、链接等等,这个脚本将运行不止一次,所以我希望它做的只是如果数据库中尚不存在“输出”作为文档,则将其作为文档插入,所有这些新文档都具有来自 job_id 变量的自己的唯一 ID,我可以对此进行检查吗?

【问题讨论】:

    标签: python python-3.x mongodb mongodb-query pymongo


    【解决方案1】:

    你需要尝试两件事:

    1) 执行.find() 并且如果没有找到给定job_id 的文档,则写入数据库是双向调用 - 相反,您可以在job_id 字段上使用unique-index,如果您的操作尝试插入重复的文档,这将引发错误(拥有唯一索引是避免重复的更安全的方法,即使您的代码逻辑失败也很有帮助)。

    2) 如果您有 30 个字典 - 您无需迭代 30 次并使用 insert_one 进行 30 次数据库调用,而是可以使用 insert_many 接收数组dict 的 & 写入数据库。

    注意: 默认情况下,所有 dict 都按照它们在数组中的顺序写入,如果 dict 因重复错误而失败,则 insert_many 在此时失败,而不会插入其余的, 所以要克服这个你需要传递一个选项 ordered=False 这样所有字典都会被插入,除了重复的。

    【讨论】:

    • 我有 insert_many 工作,但我似乎无法让 'job_id' 作为唯一索引工作,得到 "pymongo.errors.OperationFailure: Unknown index plugin '23964927' " 作为错误代码:db.jobs.create_index([('ID', job_id)], unique=True 作为代码
    • @Derpa :我还没有真正在pymongo 上工作过,但你为什么不在数据库本身上创建unique index 呢?您是否希望您的代码这样做(这通常可以在我们需要确保索引始终可用时执行(如果索引因任何更改而被删除) - 否则我们可以只在 DB 上创建一次索引然后不需要再次检查)?
    • 实际上,我不确定我是否了解唯一索引,我认为如果我从 API 中提取数据,(下周可能相同或可能略有不同),但是来自该 API 的每个帖子都有一个唯一的 ID。核对不是更容易吗?或者这就是它的作用?无论如何,在代码中这样做会很好,因为我要进行一些测试并且可能会删除几次数据
    • @Derpa :删除数据不会删除集合上的索引(删除索引或删除 collection/db 会删除索引)。因此,当下周相同的 唯一 ID 带有更新的数据时,您需要将更新的数据与现有的权利合并吗?那么你想要那个还是你只是不插入/更新下周即将到来的新数据(只是忽略)?
    • 不,现在效果很好! One 将如何与新数据合并和更新?如果您不想回答,则不必回答:)我现在实际上能够完成我的脚本,谢谢您的帮助!
    【解决方案2】:

    编辑:

    替换

    db.jobs.insert_one(output)

    db.jobs.replace_one({'ID': job_id}, output, upsert=True)

    带有工作示例的原始答案:

    replace_one()upsert=True 一起使用。您可以多次运行它,如果找不到ID,它将使用插入,如果找到则替换。这与您所要求的不太一样,因为数据总是会更新(因此较新的数据会覆盖任何现有数据)。

    from pymongo import MongoClient
    
    
    db = MongoClient()['mydatabase']
    
    for i in range(30):
        db.employer.replace_one({'ID': i},
        {
                'ID': i,
                'Title': 'jobtitle',
                'Employer' : 'company',
                'Employment type' : 'emptype',
                'Fulltime' : 'tid',
                'Deadline' : 'deadline',
                'Link' : 'webpage'
        }, upsert=True)
    
    # Should always print 30 regardless of number of times run.
    print(db.employer.count_documents({}))
    

    【讨论】:

    • 所以脚本的作用是从 API 中提取一些信息,atm 它产生大约 30 个文档,但也可能是 50 或 27 个,我想要做的是运行这个脚本一遍又一遍,但只有在集合或数据库中不存在新数据时才写入新数据,这样我就不会在数据库中得到相同信息的重复,“job_id”变量从 API 中提取唯一 ID属于每个文档中的其余信息
    • 是的,对不起,我应该解释一下。我提供的代码只是一个展示它如何工作的示例。您需要做的就是将db.jobs.insert_one(output) 替换为db.jobs.replace_one({'ID': job_id}, output, upsert=True)。我已经更新了答案。
    • @BellyBuster :这可能有效,也可能无效!!如果您今天插入了一个文档并对其进行了几次更新,那么明天重复插入将用任何新值覆盖整个文档,或者如果它们不存在于请求中,则将删除这些字段(主要是相同的)每隔一天做一次)..
    • 没错;如果这不是提问者想要的,他们将需要找到不同的方法,例如你发布的那个。
    猜你喜欢
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-04
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    相关资源
    最近更新 更多