From Data Loss to Point-In-Time Recovery: Lessons from a MongoDB Driver Bug
The Problem
A few years ago, the MongoDB driver for Node.js (https://npmjs.org/mongodb) wasn't as polished as it is now.
One of the issues that caused a serious problem for me was the update query:
db.user_views.update(<filter>, <update_statement>);
We had "one-time" scripts that we ran on the server to migrate data to a new format. In one of those scripts, I wanted to edit a single field across all documents in the "user_views" collection, but I forgot to add the $set operator in <update_statement>, so the query ended up looking like this:
db.user_views.update(
{}, // no filter — affects all documents
{} // update part — left empty by mistake
);
The problem with the driver was that instead of throwing an error — like the official mongosh (MongoDB's command-line client) would — it replaced every document with the empty object I had passed. The result: all user_views were wiped from the database. It was terrible to see what I had done.
But it wasn't a total disaster, because we had daily backups created with mongodump. I stopped the API, restored the user_views collection, and started the API again. The only data we lost were user_view documents created in the last 10 hours before the incident.
What Was Done After That
-
I checked the MongoDB documentation and confirmed that the driver was not behaving as expected.
According to the docs, a query like this — without any update operators in the update part — should not be executed:
db.user_views.update({...}, {});However, this was only enforced by the command-line utility, not by the Node.js driver.
I created a ticket in MongoDB's Jira, described the problem, and it was later fixed by the MongoDB team.
-
Since we had lost user_views from the last few hours, I needed to take steps to prevent this from happening again:
- I forked the MongoDB driver locally and added a validation check for this case, so we could use it as a safeguard until the fix landed in the official driver.
- I researched our options for incremental backups and found Percona Backup for MongoDB. I spent some time setting it up and wrote detailed documentation so that our team could follow clear instructions and act without delays if something like this ever happened again.
Note: Before sharing this document, I removed everything related to our infrastructure: replaced real server addresses with
<SERVER_ADDRESS_HERE>and changed usernames and paths.https://drive.google.com/file/d/1kMw5TEr8rQuxxQFNTY6Xsb8BCWiNuybY/view
What We Gained
- Incremental backups allowed us to significantly reduce backup storage, since we only run full backups every three days and use incremental backups in between.
- It became much easier to restore the most recent data if anything goes wrong with the database.
- These backups also turned out to be useful for our marketing team. They would occasionally need to check things like "what changed in the configuration of Feature X two weeks ago?" — they would compare subscription statistics and sometimes didn't have a log of the configuration changes they had made in our admin panel, but wanted to understand what had led to shifts in subscription numbers.