With Update Method, Toggle Boolean Field In All Documents Of A MongoDB Collection

Recently I got a situation in which I had to update all user documents in mongoDB to toggle a boolean field. I was looking for single update query that could take care of it, but being a rare need, the problem had not many helpful solutions.

I finally resorted to old-school brute force technique of using “temporary” field. This didn’t result in a single query though, but three queries, which was still a quick and acceptable solution for my one time need.

The technique is straight forward. Let’s take an example of some imaginary user docs. Some have boolean field reset with true or false. Some don’t have the field.

> db.users.find({})
{ "_id" : ObjectId("5b71d3601944d3197fd53010"), "__v" : 0 }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656289"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a8e656289"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5271d42d4b77c41a7e656289"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b7831388c89e43cc9e821ec"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656299"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5b71d42d4b88c41a7e996d87"), "__v" : 0, "reset" : false }

Step 1

Toggle reset true to false with update method and multi: true option. Additionally, add a temporary field resetToggled and set it to true.

> db.users.update({reset: true}, {$set: {reset: false, resetToggled: true}}, {multi: true});

The result looks like this:

> db.users.find({})
{ "_id" : ObjectId("5b71d3601944d3197fd53010"), "__v" : 0 }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a8e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5271d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b7831388c89e43cc9e821ec"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656299"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5b71d42d4b88c41a7e996d87"), "__v" : 0, "reset" : false }

Step 2

Set reset to false in all documents where resetToggled does not exist. This check ensures that updated documents in step 1 are not updated again.

> db.users.update({reset: false, resetToggled: {$exists: false}}, {$set: {reset: true}}, {multi: true});

At this point, all documents have been toggled:

> db.users.find({})
{ "_id" : ObjectId("5b71d3601944d3197fd53010"), "__v" : 0 }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a8e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5271d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b7831388c89e43cc9e821ec"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656299"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b88c41a7e996d87"), "__v" : 0, "reset" : true }

In case you want to treat non-existing reset field as false too, the query would become:

> db.users.update({resetToggled: {$exists: false}}, {$set: {reset: true}}, {multi: true});

And the results:

> db.users.find({})
{ "_id" : ObjectId("5b71d3601944d3197fd53010"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a8e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5271d42d4b77c41a7e656289"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b7831388c89e43cc9e821ec"), "__v" : 0, "reset" : false, "resetToggled" : true }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656299"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b88c41a7e996d87"), "__v" : 0, "reset" : true }

Step 3

Lastly, remove the temporary field from all documents:

> db.users.update({}, {$unset: {resetToggled: 1}}, {multi: true});

The final result:

> db.users.find({})
{ "_id" : ObjectId("5b71d3601944d3197fd53010"), "__v" : 0 }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656289"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5b71d42d4b77c41a8e656289"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5271d42d4b77c41a7e656289"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5b7831388c89e43cc9e821ec"), "__v" : 0, "reset" : false }
{ "_id" : ObjectId("5b71d42d4b77c41a7e656299"), "__v" : 0, "reset" : true }
{ "_id" : ObjectId("5b71d42d4b88c41a7e996d87"), "__v" : 0, "reset" : true }

TL;DR

1 Toggle True To False

> db.users.update({reset: true}, {$set: {reset: false, resetToggled: true}}, {multi: true});

2 Toggle False To True

> db.users.update({reset: false, resetToggled: {$exists: false}}, {$set: {reset: true}}, {multi: true});

3 Remove Temporary Field

> db.users.update({}, {$unset: {resetToggled: 1}}, {multi: true});