Reputation: 620
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
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
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