Tim
Tim

Reputation: 99478

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

In my collection, there is only one document.

> db.c20160712.find()
{ "_id" : ObjectId("57ab909791c3b3a393e9e277"), "Dimension_id" : 2, "Attribute" : "good", "Hour" : "20160712_06", "Frequency_count" : 100 

I want to run updateOne to replace the document with another one. But why is there Error: the update operation document must contain atomic operators?

> db.c20160712.updateOne( { "Attribute" : "good"}, {"Type" : "DVD", "Title" : "Matrix, The", "Released" : 1999, "Genre" : "Action"}, { upsert: true} )
2016-08-10T16:37:57.089-0400 E QUERY    [thread1] Error: the update operation document must contain atomic operators :
DBCollection.prototype.updateOne@src/mongo/shell/crud_api.js:493:1
@(shell):1:1

The second and third arguments in the above command comes from an example in The Definitive Guide to MongoDB: A complete guide to dealing with Big Data ... By Eelco Plugge, David Hows, Peter Membrey, Tim Hawkins

My MongoDB is 3.2.

Upvotes: 162

Views: 224715

Answers (5)

Ja3Gade
Ja3Gade

Reputation: 9

If you want to update all then use empty curly braces before $set example:-

db.student_info.updateMany({},{$set:{"fine":0,"maxbook":3}},{upsert:true})

I faced the same error because I use this:-

db.student_info.updateMany({$set:{"fine":0,"maxbook":3}},{upsert:true}) 

Upvotes: 0

Juan Lanus
Juan Lanus

Reputation: 2344

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.

Upvotes: 5

Nagender Pratap Chauhan
Nagender Pratap Chauhan

Reputation: 2204

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;

Upvotes: 48

dyouberg
dyouberg

Reputation: 2332

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.

Upvotes: 50

Alex Blex
Alex Blex

Reputation: 37048

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 }
);

Upvotes: 220

Related Questions