Ten questions on the document model, queries, the aggregation pipeline, indexes, schema validation, transactions and Mongoose 243,355 . Every one of them turns on behavior that has surprised somebody in production, and most of them have cost somebody a night. Write down your answer before you run anything; the answers, with the reasoning and the section that covers each one, are in Appendix G.
To check your work, start a server of your own rather than sharing one: mongod --port 28134 --dbpath <a fresh directory> gives you a scratch instance you can throw away, and adding --replSet rs0 plus a single rs.initiate() is what makes Question 9 runnable at all. Connect with ?directConnection=true when you do, or the driver will spend thirty seconds looking for the other members of a replica set that has none, and stop the server by its process id when you are finished rather than leaving it holding the data directory.
Queries, aggregation and indexes
Questions 1 to 7 run in mongosh 403 against MongoDB 8.3 1,815 . The books collection holds exactly three documents: The Hobbit (price 14, editions [{format:'ebook',pages:310},{format:'hardcover',pages:320}]), Snow Crash (price '11.25' — a string, not a number — with discount: null and one ebook edition of 440 pages) and Project Hail Mary (price 15, one ebook edition of 476 pages). No other document has a discount field at all, and no index exists beyond _id_.
// 1. Three counts over three documents. What are the three numbers, and which of the
// three filters is the one you almost never want to write?
db.books.countDocuments({ discount: null });
db.books.countDocuments({ discount: { $exists: false } });
db.books.countDocuments({ discount: { $exists: true, $ne: null } });
// 2. These two filters read the same in English: an ebook edition longer than 315 pages.
// Which titles does each one return, and which title is the difference between them?
db.books.find({ 'editions.format': 'ebook', 'editions.pages': { $gt: 315 } });
db.books.find({ editions: { $elemMatch: { format: 'ebook', pages: { $gt: 315 } } } });
// 3. The cheapest book on the shelf costs 11.25. Which titles come back from each of these
// three, and which document ends up first in the sorted list?
db.books.find({ price: { $lt: 12 } });
db.books.find({ price: { $not: { $gte: 13 } } });
db.books.find().sort({ price: -1 });
// 4. One of these two projections fails. Which one, with what message, and what is the
// single exception to the rule it breaks?
db.books.find({}, { title: 1, price: 0 });
db.books.find({}, { title: 1, _id: 0 });The next three leave querying behind: one on how BSON stores what you give it, one on the stage that silently loses documents, and one on the index option that silently loses them too.
// 5. Four BSON sizes in bytes. Two of the four are equal - which two, and what does that
// tell you about how BSON stores an array? Why is the second one larger than the first?
bsonsize({ n: 7 });
bsonsize({ n: Double(7) });
bsonsize({ t: ['scifi', 'classic'] });
bsonsize({ t: { 0: 'scifi', 1: 'classic' } });
// 6. Collection `t` holds {_id:1,t:['a','b']}, {_id:2,t:[]}, {_id:3} and {_id:4,t:'x'}.
// How many rows does this emit, which _ids appear, and what happens to _id 4?
db.t.aggregate([{ $unwind: '$t' }]);
// 7. Collection `c` holds four documents; two of them have no `coupon` field. The two
// lines below return different numbers of documents. Which numbers, and which is wrong?
db.c.createIndex({ coupon: 1 }, { sparse: true, name: 'sp' });
db.c.find().sort({ coupon: 1 }).toArray().length;
db.c.find().sort({ coupon: 1 }).hint('sp').toArray().length;Three of these seven need nothing but a shell. Question 5 runs entirely client-side, since bsonsize() only serializes what you hand it. Questions 2, 3 and 7 are settled by appending .explain('executionStats') and reading nReturned, totalKeysExamined and totalDocsExamined: when a filter that looks obviously correct returns the wrong documents, the plan tells you which index — or which none — the server used to decide.
Validation, transactions and Mongoose
Questions 8 to 10 use the Node.js 2,131 driver 7.6 and Mongoose 9.10 against the same server, running as a single-node replica set so that sessions and transactions work.
// 8. Collection `t8` already holds { _id: 1, email: 'bad' }, written before the rule below
// existed. Which of the two writes is accepted, which is rejected, and with what code?
db.runCommand({ collMod: 't8', validationLevel: 'moderate', validator: { $jsonSchema: {
required: ['email'], properties: { email: { bsonType: 'string', pattern: '@' } } } } });
db.t8.updateOne({ _id: 1 }, { $set: { name: 'x' } });
db.t8.insertOne({ _id: 3, email: 'nope' });
// 9. `ledger` has a unique index on `ref` and already holds { ref: 'tx-1' }. Accounts A and
// B start at 100 and 40. What are the two balances afterwards - and what would they be
// if every `{ session }` option were deleted and withTransaction replaced by a for loop?
await session.withTransaction(async () => {
await accounts.updateOne({ _id: 'A' }, { $inc: { bal: -25 } }, { session });
await accounts.updateOne({ _id: 'B' }, { $inc: { bal: 25 } }, { session });
await ledger.insertOne({ ref: 'tx-1' }, { session });
});
// 10. The Book schema declares title, slug and tags, and carries one hook:
// schema.pre('save', function () { this.slug = slugify(this.title); });
await new Book({ title: 'The Cyberiad' }).save();
await Book.insertMany([{ title: 'Peace on Earth' }]);
await Book.findOneAndUpdate({ title: 'The Cyberiad' }, { title: 'Return from the Stars' });
// How many times did the hook run, which stored document ends up with a slug, and what is
// that slug? And what type is `_id` on a document read back with .lean()?