48

I want to add a record to the collection if the key doesn't already exist. I understand [MongoDB][1] offers the upsertfor this so I did a

db.collection.update({"_id":"key1"},{"_id":"key1"},True) 

This seems to work.

However in the Pymongo documentation it says that update is deprecated and use to update_one().

But:

db.collection.update_one({"_id":"key1"},{"_id":"key1"},True)

Gives:

raise ValueError('update only works with $ operators')
ValueError: update only works with $ operators

I don't really understand why update_one is different and why I need to use a $ operator. Can anyone help?

styvane
  • 59,869
  • 19
  • 150
  • 156
johhny B
  • 1,342
  • 1
  • 18
  • 37

2 Answers2

75

This is because you didn't specify any update operator. For example to $set the id value use:

db.collection.update_one({"_id":"key1"}, {"$set": {"id":"key1"}}, upsert=True)

Note that in the Mongo shell, this will simply replace the document with the new document.

styvane
  • 59,869
  • 19
  • 150
  • 156
37

Use replace_one() instead of update_one(). the 3rd parameter of replace_one() is upsert, too.

db.collection.replace_one({"_id": "key1"}, {"_id": "key1"}, True) 

My personal opinion is this implementation of update_one() is inconsistent with the behaviour of MongoDB client. The upsert option in update_one() is actually meaningless. But the developers of pyMongo may just want to use this to distinguish update_one() and replace_one().

George Lei
  • 467
  • 5
  • 5
  • 2
    Thank you, your answer saved me a lot of headache. It was unclear from the docs that the same call with `update_one` is invalid and `replace_one` is. Applies to the C++ driver, too, by the way. – Violet Giraffe Oct 06 '18 at 15:12
  • 2
    They are different. Replace_one always replace the data, update_one can update some fields of the record. – hernan Jun 22 '20 at 17:40