在 PyMongo 中,如果找到,如何获取文档的 _id,否则插入并获取插入文档的 _id

In PyMongo, how to get the _id of the document if found, else insert and get the _id of the inserted document

例如:

我有一个collection'stories' 每个文档的格式为:

{
  '_id': <default>
  'story': <some very long string which should be unique in the collection>
}

现在每当我有一个故事时,如果它已经存在于 'stories' 中,我想要它的 '_id',否则插入一个带有 'story' 字段集的新文档,并获取它的 '_id'

我能想到的是:

story = "this is a very long story"
id = stories_col.find_one_and_update({
    'story': story,
}, {
    'story': story,
}, upsert=True, return_document=ReturnDocument.AFTER)['_id']

这不是很低效吗,因为它会更新(修改)文档,即使它不是必需的?可以提高效率吗

您唯一可以做得更好的是定义一个函数,例如:

def make_sure_exists(story, stories_col):
    data = stories_col.find_one({'story': story})
    if data is not None:
        return data.['_id']
    return stories_col.insert_one({'story': story}).inserted_id

除非你有足够新的 mongo 版本,在这种情况下你可以使用 $setOnInsert 操作:

story = "this is a very long story"
id = stories_col.find_one_and_update({
    'story': story,
}, {
    'story': { '$setOnInsert': story }
}, upsert=True, return_document=ReturnDocument.AFTER)

您参与其中,使用$setOnInsert修改更新操作:

story = "this is a very long story"
id = stories_col.find_one_and_update({
    'story': story,
}, {
    '$setOnInsert': { 'story': story }
}, upsert=True, return_document=ReturnDocument.AFTER)

这意味着如果文档匹配,那么将执行 "no actual" 写入,因为这里唯一有效的操作是 "on insert"。

通常建议 "always" 使用适合您的操作的 update operators,因为您使用 "always" 的 "raw" 对象替换了 "everything"没有它们的文档。