Ashish
Ashish

Reputation: 620

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

For ex:

I have a collection 'stories' where each document is of the form:

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

Now whenever I have a story, If it already exists in 'stories', I want its '_id', else insert a new document with 'story' field set, and get its '_id'

What I could come up with, is:

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']

Isn't this inefficient as it will update (modify) a document, even if it's not required? Can this be made more efficient

Upvotes: 1

Views: 1650

Answers (2)

Blakes Seven
Blakes Seven

Reputation: 50406

You were part of the way there, use $setOnInsert to modify the update operation:

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)

That means that if the document is matched then there will be "no actual" write performed as the only valid action here is "on insert".

It is generally advisable to "always" use the update operators appropriate to your action, because a "raw" object as you used "always" replaces "everything" in the document without them.

Upvotes: 5

CrazyCasta
CrazyCasta

Reputation: 28302

The only thing you could do better would be to define a function like:

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

Unless you have a new enough version of mongo in which case you can use the $setOnInsert operation:

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)

Upvotes: 1

Related Questions