$in, $nin and $exists
A customer ticks two genres on the filter panel: "myth" and "romance". Another wants anything except sci-fi. A data check needs every book that has never been rated. These are membership and presence questions, and three operators handle them.
The rule
$in: any of these. $nin: none of these. $exists: is it there at all?
| _id | title | year | price | stock | genres |
|---|---|---|---|---|---|
| 1 | Dune | 1965 | 9.99 | 12 | sci-fi, classic |
| 2 | Neuromancer | 1984 | 8.5 | 0 | sci-fi, cyberpunk |
| 3 | Emma | 1815 | 4.25 | 7 | classic, romance |
| 4 | The Hobbit | 1937 | 7.99 | 3 | fantasy, classic, adventure |
| 5 | Circe | 2018 | 12 | 5 | fantasy, myth |
Dune, Neuromancer, Emma and The Hobbit have a ratings array (Emma's is empty, []); Circe has no ratings field. Only The Hobbit has signed: true.
db.books.find({ genres: { $in: ["myth", "romance"] } }) // Emma, Circe
db.books.find({ _id: { $in: [1, 3, 9] } }) // Dune, Emma (no book 9)
db.books.find({ genres: { $nin: ["sci-fi", "fantasy"] } }) // Emma
db.books.find({ ratings: { $exists: false } }) // Circe
db.books.find({ signed: { $exists: true } }) // The Hobbit$inmatches if the field equals any value in the list. On an array field, any element may match any listed value. It is a neater form of several equality tests on one field.$ninmatches if the field equals none of the values, including when the field is missing, just like$ne.$exists: truematches documents that have the field, whatever its value, evennullor[].$exists: falsematches documents without it.
The shortcut
For $nin, cross out every document that contains a listed value; whatever survives matches, including documents missing the field.
Cross out sci-fi
Dune and Neuromancer contain "sci-fi". Out.
The trap is reading $exists: true as "has a useful value". Emma's empty ratings array exists, so it matches.
Drills
Answer fast — trust the rule.
How many books match { genres: { $in: ["myth", "romance"] } }?
How many books match { ratings: { $exists: true } }?
Which filter returns books that are NOT by Frank Herbert or William Gibson?
How many books match { signed: { $nin: [true] } }?
Remember
- $in: any of these. $nin: none of these. $exists: is it there at all?
- Shortcut: for
$nin, cross out anything holding a listed value; the survivors match. - Trap:
$ninmatches missing fields, and$exists: truematches empty or null values.
