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, similar to the way we use in programming tasks. This of course required more than a single query though, 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
}
);
See also
- Node JS Mongo Client for Atlas Data API
- Exactly Same Query Behaving Differently in Mongo Client and Mongoose
- MongoDB Single Update Query to Change the Field Name in All Matching Documents of the Collection
- Clean Up MongoDB Of Old Inactive Users And Their Data With Node Js Script
- Build Queue For Processing Webhooks With Node Js And MongoDB
- Intercept Node JS Console Log and Insert in MongoDB
- Export MongoDB Collection Data In CSV From Node Express Mongoose Application