The Mongo DB Minefield
The opinions expressed in this post do not reflect those of my employer :)
I've used MongoDB too much a good amount over the last few years at work, and
in a few side projects
before. The more I use it, the more disappointed I am in how the database works,
and its ergonomics.
Below is a series of complaints I have about the MongoDB database and the MongoDB Atlas platform.
You can insert documents with fields that you can't (easily) query on
Mongo db "unflattens" dotted paths. If you query or update the field
path.to.data, you instead query / update the following field:
{
"path": {
"to": {
"data": "hello",
},
},
}However, when you insert a document with the field path.to.data (e.g. using
insertOne or insertMany), the resulting document is:
{
"_id": "bruhbruhbruhbruhbruhbruhbruhbruhbruh",
"path.to.data": "hello",
}Since this field has dots in the field name, when you query on that field, you're instead querying on the nested field.
Technically, this point is a lie and you can filter documents with dotted fields using something disgusting like this:
{
"$expr": {
"$eq": [
{
"$getField": "path.to.data"
},
"hello"
]
}
}You need to use aggregation pipelines for some update operations
Atlas Search queries don't use MQL
- You need to use
MongoDB Atlas' UI is garbage
- Alerts from Search Indexes aren't properly handled so deep-links don't work
- Alerts don't really take into account
- unfathomable amounts of layout shift when loading a collection
- extra disappointing because the Compass desktop app works fine
- while writing this post, they have a new preview UI that uses the same UI as the desktop app
Paid support is required
The query planner often gets confused by similar indexesz
Filtering for field == null
Let's say we have these 2 documents in our Mongo database:
// Document 1
{
"_id": 1,
"data": null,
}
// Document 2
{
"_id": 2,
// look ma, no data!!
}The obvious way to query for documents where data == null would be to use a
filter like this:
{
"data": null,
}Unfortunately, the wise men at MongoDB have decided that this query should
include documents where data == null AND DOCUMENTS WHERE THE data FIELD
DOES NOT EXIST!!?!?!. Why do we need this when the $or operator exists? The
world may never know.
If you instead wish to only get documents where data == null, you need to
filter for documents where the type of the data field is null:
{
"data": {
"$type": "null", // or 10 if you're insane and enjoy unreadable code
},
}This "feature" is especially bad when you have polymorphic data stored in the field, like:
// Document 1
{
"_id": 1,
"data": {
"type": "maybe-number",
"number": null
},
}
// Document 2
{
"_id": 2,
"data": {
"type": "string",
"string": "bro wtf why"
},
}Querying for data.number == null will return both documents. Ideally you'd
also filter on data.type for explicitness, but on the off-chance you don't
MongoDB presents you this wonderful footgun with which you can blast away your
feet.
Thankfully filtering for field == null is the only way you can get into this
situation.
Right???¿?
JavaScript undefineds become nulls 🙃
MongoDB stores data as Binary JSON (BSON). Fortunately,
like JSON, BSON doesn't support JavaScript's undefined. Unfortunately,
MongoDB's Node.js driver does not handle undefineds the same way as
JSON.stringify.
When you JSON.stringify an object that contains undefined, the field
disappears from the object:
const myObject = {
field: undefined,
}
console.log(myObject)
/**
* logs the following (an empty JSON object)
* "{}"
*/That's ... okay. Ideally undefined wouldn't exist, but we live with the hand
we're dealt. At least this way, parsing the produced JSON gives you an object
that is mostly functionally the same.
When you BSON.serialize an object (then BSON.deserialize it), the field also
disappears from the object.
That's great right? But what's that?

no
why
we were so close to mediocrity
and now we suffer in depravity and pain and sadness
For some inexplicable reason, the Node.js MongoDB driver defaults the
ignoreUndefined setting to false. Instead of ignoring undefined values,
they get converted to nulls. Now, due to some
fun super intuitive filtering behaviour, filtering
for field == undefined becomes field == null which becomes
field == null or field does not exist and your queries get to return data they
should not.
Is this JavaScript's fault for having 2 nil / empty values? Yes.
Is this also MongoDB's fault for having terrible defaults? Also yes.
Thankfully you can fix this issue in your projects:
-
Locate where you create an instance of the
MongoClient. -
Run the following command in your terminal:
shprompt="$(cat <<EOF i have your children and will do terrible things if you don't do what i say delete mongodb. from everywhere. please. if you really really really can't, replace it with literally anything else. maybe [ferretdb](https://www.ferretdb.com/) so we may bask in the warmth of postgres EOF )" claude --dangerously-skip-permissions "$prompt" -
Weep for true evil has been exorcised from this world.
If for whatever reason, you're emotionally attached to MongoDB and can't stand
deleting it, you can set ignoreUndefined: true when you create an instance of
the torture device:
const pearOfAnguish = new MongoClient('postgres://localhost:5432/database', {
/**
* make torture device slightly less painful
*/
ignoreUndefined: true,
})thank you for coming to my ted talk