Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error: the update operation document must contain atomic operators, when running updateOne

Tags:

mongodb

People also ask

Is updateOne Atomic?

updateOne()A write operation on a single document in MongoDB is atomic. When fields must be updated at the same time, embedding them within the same document ensures that the fields can be updated atomically.

What is atomic operation in MongoDB?

In MongoDB, a write operation is atomic on the level of a single document, even if the operation modifies multiple embedded documents within a single document.


Wrong syntax for the second parameter. Please check the docs. It should be:

db.c20160712.updateOne(
    { "Attribute" : "good" }, 
    { $set: {"Type" : "DVD", "Title" : "Matrix, The", "Released" : 1999, "Genre" : "Action" } },
    { upsert: true }
);

I believe this was changed as a side-effect of introducing the updateOne() method in addition to update() and updateMany() as somewhat of a safeguard to prevent user's from accidentally overriding an entire document.

You can use the replaceOne() method instead, or an update() without specifying multi:true.


You should use this code because I was also facing the same problem and then I used this code:

updateOne(
    { _id: new ObjectID(req.params.id) },
    { $set: { title: req.body.bookName, author: req.body.authorName } },
    { upsert: true }
)

and you should also define ObjectID otherwise the problem will occur again.

const ObjectID = require('mongodb').ObjectID;

There are the "replaceX" methods, and the "updateX" methods.

The answer by @Alex Blex is of the update kind, while the PO was attempting (in 2016) to replace. Both are valid, albeit they work a bit differently.

The updateX methods, in their second argument, want a document like Alex's: { $set: {"Type" : "DVD"... } where I guess that $set is an instance of the atomic operators mentioned in the error msg.
With update you can target individual properties of the DB document, leaving the others unchanged.

The replace methods take a complete document as the second operand, intended to totally replace the current document existing in the DB.
In this case the second argument is simply the new document, in full. No $set or others (there are several, to delete, increment, ...).

In all cases, the first argument is a MongoDB search document, in my case I use the _id and prepare it like so:
let searchDoc = { _id: ObjectID( _id )};
As @nagender pratap chauhan mentioned, you can't use the _id's string value for matching.
Also, there is some confussion with ObjectID and ObjectId (upper- or lower- case "D").

The third argument, optional, contains the options.
In the case of the updateOne method, stating
{ upsert: true}
means that, in case there are no documents satisfying the search criteria stated in the first argument, Mongo should create it.

My code is like so:

let searchDoc = { _id: ObjectID( _id )};
this.data = await DAO.db.collection( 'authors' )
.replaceOne(
    searchDoc,                  // filter
    authorData,                 // replacement doc (a JS object)
    {                           // options
        returnOriginal: false,
        sort: [['_id', -1]],
    }
);

return this.data;               // the stored author

The _id field must not be present in the replacement document, else Mongo would complain about trying to change an immutable field, even if the value is the same as the existing one.