Documentation Index
Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
Use this file to discover all available pages before exploring further.
Databases & Collections
In MongoDB, data is organized in a three-level hierarchy. Think of it like a physical office building:- A Database is an entire filing room — a dedicated space for one application or domain.
- A Collection is a filing cabinet drawer in that room — it holds documents of a similar type (users, orders, products).
- A Document is a single folder in the drawer — one self-contained record with all its details inside.
| MongoDB Term | SQL Equivalent | Analogy |
|---|---|---|
| Database | Database | A filing room |
| Collection | Table | A cabinet drawer |
| Document | Row | A folder in the drawer |
| Field | Column | A labeled sheet inside the folder |
phone field; another might not. The collection does not enforce uniformity unless you explicitly add validation rules.
Creating a Database
In MongoDB, you don’t explicitly “create” a database. You switch to a name and start inserting data — MongoDB creates the database lazily when the first document is written. This is like labeling an empty room: the room exists the moment you put something in it, not when you write the name on the door. Usingmongosh (MongoDB Shell):
Creating a Collection
Similarly, collections are created when you first insert data into them — another example of MongoDB’s lazy creation philosophy.Naming Conventions
MongoDB has rules for database and collection names that are worth knowing before you run into cryptic errors: Database names:- Cannot contain
/\. "$*<>:|?or the null character - Are case-sensitive (
MyAppandmyappare different databases) - Maximum 64 characters
- Avoid names that differ only by case — some file systems are case-insensitive
- Cannot contain the null character or start with
system.(reserved) - Cannot contain
$(reserved for internal use) - Should be lowercase with underscores or camelCase — pick one convention and stick with it
Dropping
Dropping is permanent. There is no “undo” in MongoDB for drop operations. Always verify you are connected to the correct database and cluster before dropping anything.Drop Database
Drop Collection
Document Structure
Documents are BSON objects. Unlike SQL rows, a document can contain nested objects (embedded documents) and arrays — this lets you store related data together rather than spreading it across multiple tables.The _id Field
Every document must have a unique _id field.
- If you don’t provide one, MongoDB generates a unique
ObjectIdautomatically. - It is the primary key for the document.
- It is immutable (cannot be changed after insertion).
- MongoDB automatically creates a unique index on
_id— you never need to create one yourself.
Practical Patterns: Embedding vs. Referencing
One of the first design decisions in MongoDB is whether to embed related data inside a document or reference it by_id from another collection.
Document Size Limits
MongoDB enforces a 16 MB maximum document size. This is generous for most use cases, but it means you should not embed unbounded arrays (e.g., every comment on a viral post). If an array can grow without limit, use a separate collection and reference by_id.
Indexing Tip for Document Design
Your document structure directly affects what you can index efficiently. If you embed data, you can create indexes on nested fields:Summary
- Databases hold collections. Collections hold documents. Documents are the data records (JSON/BSON).
- Databases and collections are created lazily — they spring into existence when the first document is inserted.
- Every document has a unique
_idwith an automatic index. - Embed related data when it is read together and bounded in size; reference when it is shared or unbounded.
- Document size is capped at 16 MB — design your schema to respect this limit.
- You can index nested fields and array fields using dot notation.
Interview Deep-Dive
You are designing a social media platform's data model in MongoDB. A User has a profile, posts, followers, and a message inbox. Walk me through your embedding versus referencing decisions for each relationship.
You are designing a social media platform's data model in MongoDB. A User has a profile, posts, followers, and a message inbox. Walk me through your embedding versus referencing decisions for each relationship.
Explain how MongoDB's ObjectId is generated. Why is it designed this way, and what can you extract from an ObjectId without querying the database?
Explain how MongoDB's ObjectId is generated. Why is it designed this way, and what can you extract from an ObjectId without querying the database?
- An ObjectId is a 12-byte (24 hex character) unique identifier. Its structure is intentional and encodes useful metadata. The layout is: 4 bytes for the Unix timestamp (seconds since epoch), 5 bytes for a random value unique to the machine and process, and 3 bytes for an incrementing counter initialized to a random value.
- This design solves a hard distributed systems problem: generating globally unique IDs without a central coordinator. In a sharded cluster with 50 mongos routers handling concurrent inserts, no two of them will generate the same ObjectId because the random component differentiates machines and the counter handles same-second collisions on the same machine.
- What you can extract without querying: the creation timestamp.
ObjectId("507f1f77bcf86cd799439011").getTimestamp()returns the exact second the document was created. This means you get a freecreatedAtfield on every document without explicitly storing one. You can also sort by_idto get chronological order, and you can query by time range using ObjectId comparisons, which is faster than date comparisons because_idhas a unique index by default. - There is a practical trick: if you want to find all documents created after January 1, 2024, you can construct a minimum ObjectId for that date and query
{ _id: { $gt: ObjectId("timestamp000000000000000000") } }. This uses the_idindex directly, avoiding a separate date index. - One important change: in MongoDB 3.4 and earlier, the middle bytes encoded the machine identifier and process ID, which could leak infrastructure information. MongoDB 5.0+ changed this to a random value, which is more secure but means you can no longer determine which server generated a particular ObjectId.
- Custom IDs make sense when you have a natural unique identifier that your application already uses. For example, a
userscollection where every user has a unique email address — you could use{ _id: "alice@example.com" }. This eliminates the need for a separate unique index on email. - Another common case: importing data from another system that already has unique IDs. If you are migrating from PostgreSQL and your orders have sequential integer IDs referenced by external systems (payment processors, shipping APIs), it is pragmatic to use
{ _id: existingOrderId }to avoid maintaining a mapping table. - The risks are real though. If your custom ID is monotonically increasing (like an auto-incrementing integer), all inserts go to the same chunk on the last shard in a sharded collection. This creates the “hot shard” problem. ObjectIds avoid this because the random component distributes inserts across chunks.
- Another risk: if your custom ID can change (like an email address), you have a problem because
_idis immutable in MongoDB. You would need to delete and reinsert the document, which breaks any references to that_idfrom other collections. - My rule: use custom IDs when the identifier is truly immutable, naturally unique, and your primary lookup key. Otherwise, stick with ObjectId and create a secondary unique index on your business identifier.
What is a capped collection in MongoDB? Describe a production use case where it is the right choice, and explain why a regular collection with a TTL index would NOT be a suitable alternative.
What is a capped collection in MongoDB? Describe a production use case where it is the right choice, and explain why a regular collection with a TTL index would NOT be a suitable alternative.
- A capped collection is a fixed-size collection that works like a circular buffer. Once it reaches its size limit (specified in bytes) or document count, the oldest documents are automatically overwritten by new inserts. The insertion order is preserved, and documents cannot be deleted individually or updated in a way that increases their size.
- The production use case where capped collections genuinely shine is high-throughput logging with strict insertion-order guarantees and predictable performance. Consider an application-level log pipeline that writes 10,000 events per second. A capped collection of 5 GB gives you the most recent few hours of logs, automatically purged, with no background deletion process, no index overhead for deletion, and guaranteed insertion-order reads.
- Why a TTL index is not a suitable alternative in this specific case: TTL indexes rely on a background thread (
TTLMonitor) that runs every 60 seconds by default and deletes expired documents. Under heavy write load, the TTL monitor can fall behind, causing the collection to grow unboundedly until the monitor catches up. I have seen TTL-indexed collections balloon to 50 GB when the expected steady state was 5 GB, because the deletion rate could not keep up with the insertion rate during a traffic spike. - Capped collections avoid this entirely because the deletion is part of the write path itself — the old document is overwritten atomically, so the collection size is guaranteed to never exceed the cap. There is no background process that can fall behind.
- The trade-offs of capped collections are significant though. You cannot shard them. You cannot delete individual documents (only the collection as a whole). Updates that increase document size fail. You cannot add indexes that would be useful for arbitrary queries (though you can index fields for read queries). And if you need to keep specific documents permanently, a capped collection is fundamentally wrong because everything eventually gets overwritten.
- Capped collections also power MongoDB’s internal replication mechanism — the oplog (
local.oplog.rs) is a capped collection. This is the canonical example of where the circular buffer behavior is exactly what you want: a finite window of recent operations that secondaries replay to stay in sync.
- This is a common architectural decision. The answer depends on whether you need consumers to process events or just store them for querying.
- Capped collection wins when: you primarily need queryable recent logs (find all errors in the last hour, search by request ID), you do not need multiple consumers processing the events, and you want zero additional infrastructure. It is just another MongoDB collection.
- Kafka wins when: you have multiple consumers that need to process each event independently (alerting service, analytics pipeline, audit log archiver), you need event replay (a new consumer can read from the beginning of a topic), or you need ordering guarantees per partition at massive scale (millions of events per second).
- The pragmatic middle ground: use MongoDB Change Streams as a lightweight event stream. Write to a regular collection, and Change Streams give you a real-time feed of changes that multiple consumers can subscribe to. You get queryable storage and event-driven processing without adding Kafka to your infrastructure. The limitation is that Change Streams require a replica set and have a finite oplog window — if a consumer falls too far behind, it loses its position.
A developer on your team drops a collection in production by accident. Walk me through the incident response and how you would prevent this from happening again.
A developer on your team drops a collection in production by accident. Walk me through the incident response and how you would prevent this from happening again.
- Immediate response, in order. First, assess the blast radius: which collection was dropped, how large was it, and which services depend on it. Alert the team immediately — do not try to fix it silently.
- Second, restore from backup. If you are on Atlas, use the point-in-time restore feature to recover the collection to the moment before the drop. Atlas retains continuous backups for the cluster tier you are on (typically 7 days of point-in-time, plus daily snapshots). If you are self-hosted, restore from your most recent mongodump or filesystem snapshot. The gap between the last backup and the drop is your data loss window.
- Third, if you have a replica set and the oplog still contains the insert operations for the lost data, you can theoretically replay the oplog to reconstruct the collection. This is a complex, manual process and should only be attempted by someone experienced with oplog replay.
- Prevention measures, in order of impact. First, implement role-based access control (RBAC). Production database users for your application should have only the permissions they need:
readWriteon specific databases, neverdbAdminordbOwner. The only users with drop permissions should be DBAs operating through a controlled runbook. - Second, require multi-factor approval for destructive operations. MongoDB Atlas supports audit logging and you can configure alerts on
dropCollectionanddropDatabaseevents. Better yet, use a database proxy or policy engine that intercepts destructive commands and requires approval from a second engineer. - Third, enforce a “no direct shell access to production” policy. All schema changes (including drops) go through a migration framework (like migrate-mongo) that is version-controlled, code-reviewed, and tested in staging before production.
- Fourth, test your backup restoration process regularly. A backup you have never tested restoring is not a backup — it is a hope.
- The data loss is every write to that collection in the 6-hour window between the backup and the drop. To estimate: check your application’s write throughput metrics. If the collection receives an average of 1,000 inserts per minute, the loss is approximately 360,000 documents. If write throughput varies by time of day, use the actual metrics from your monitoring system (Datadog, Grafana, Atlas monitoring) for that specific 6-hour window.
- Communication to stakeholders should be factual and structured: what happened, what data was lost, what data was recovered, what is the customer impact, and what is the remediation timeline. Avoid vague language. “We lost approximately 360,000 order records from the last 6 hours” is better than “we lost some data.”
- If the lost data was generated by user actions (orders, messages), check if the application has other data sources that captured the same information — API gateway logs, payment processor records, message queue dead letter queues. You may be able to reconstruct a significant portion of the lost data from these secondary sources.
- The post-mortem should focus on reducing the Recovery Point Objective (RPO). If 6 hours of data loss is unacceptable, you need more frequent backups (Atlas supports continuous backup with 1-second granularity on M10+ tiers) or a real-time replication strategy to a secondary data store.