What is MongoDB?
MongoDB is a database — a program whose only job is to store your application's data safely on disk and hand it back quickly when you ask for it. What makes it different from the databases most students meet first, such as MySQL or Oracle, is the shape it stores data in. Instead of rows inside a fixed table, MongoDB stores documents: self-contained records that look almost exactly like JavaScript objects.
The label attached to MongoDB is NoSQL, and that name confuses people. It does not mean "no queries". MongoDB has a rich query language of its own; it simply is not SQL. A more honest reading of the label is "not a table-and-row database".
Internally a document is stored as BSON, short for Binary JSON. BSON is a compact binary encoding of the same structure you see as JSON, plus a few types that plain JSON lacks: a real date type, 64-bit integers, a decimal type suitable for money, and ObjectId. Those extra types are not decoration. They are the reason you can ask MongoDB for "every order placed after 1 January" and get a correct answer, instead of comparing date strings character by character and hoping.
- Document-oriented — one record holds a whole object, including nested objects and arrays
- Schema-flexible — two documents in the same collection are allowed to have different fields
- Deeply queryable — you can filter, sort and aggregate on nested fields and on individual array elements
- Horizontally scalable — designed to spread data across many machines when one machine is no longer enough
- A natural fit for JavaScript — a document has the same shape as a JS object, which is why MongoDB and Node.js are so often used together
Documents, Collections and Databases
Three words cover almost everything you will do in this course. A document is a single record: one user, one order, one product. A collection is a named group of documents, rather like a folder holding many files. A database is a named group of collections. One MongoDB server can host many databases, but a typical application uses just one.
Look at the document below and read it as an object rather than as a row. The fields name and email hold strings, age holds a number, hobbies holds an array, and address holds another object nested inside. In a relational database that address would normally be a second table joined back to the first. In MongoDB it simply lives inside the record it belongs to, and one read fetches the whole thing.
// One document from a `users` collection
{
_id: ObjectId("507f1f77bcf86cd799439011"),
name: "Ananya Sharma",
email: "ananya@example.com",
age: 22,
hobbies: ["reading", "coding", "badminton"],
address: {
city: "Pune",
state: "Maharashtra",
pincode: "411001"
},
joined: ISODate("2026-01-15T09:30:00Z")
}
// The same idea in the shell:
// database -> collection -> document -> field
// shopDB -> users -> { ... } -> email Every Document Has an _id
Every document in every collection carries an _id field, and its value must be unique inside that collection. If you do not supply one, MongoDB creates an ObjectId for you — a 12-byte value whose first four bytes are the timestamp of the moment it was generated. That detail is quietly useful: sorting by _id gives you roughly oldest-to-newest ordering even if you forgot to store a date, and getTimestamp() will tell you when a document was created.
You are also free to set _id yourself, and sometimes you should. If your records already have a natural unique key — a student roll number, an invoice number your billing system issues, an email address — using it as _id saves you a second index and makes lookups obvious to read. The one hard rule is that _id cannot be edited after insertion. "Changing" it means deleting the old document and inserting a new one, so pick a natural key only when you are confident it will never need to change.
// MongoDB fills in _id when you leave it out
db.users.insertOne({ name: "Ananya", email: "ananya@example.com" })
// { acknowledged: true, insertedId: ObjectId("...") }
// An ObjectId knows when it was made
const id = ObjectId()
id.getTimestamp() // ISODate of creation time
// Or supply your own _id when a natural key exists
db.students.insertOne({ _id: "ROLL-2026-118", name: "Rahul", branch: "CSE" }) _idis indexed automatically. It is the one index you never have to create, and it is why fetching a document by_idstays fast even in a collection holding millions of records.
How It Maps to SQL Ideas
If you have already studied SQL, the vocabulary translates almost one-to-one, and it is worth fixing that mapping in your head before you write any queries.
The one row in that mapping that is not a simple rename is JOIN. A relational database keeps related data in separate tables and stitches them together at query time. MongoDB gives you two choices instead: put the related data inside the document (embedding), or store an id and fetch the other collection separately (referencing). Choosing between those two is the single most important design decision in a MongoDB project, and two later lessons are devoted to it.
- Table → Collection
- Row → Document
- Column → Field
- Primary key → the
_idfield - JOIN → embedding the related data, or referencing it and using
$lookup - GROUP BY / HAVING → stages in the aggregation pipeline
- Schema declared with CREATE TABLE → schema decided by your application, and optionally enforced with a validator
Schema-Flexible Does Not Mean Schema-Free
MongoDB will happily accept two documents in the same collection with completely different fields. Beginners often read that as "MongoDB has no schema", which is the most expensive misunderstanding in this course. Your data always has a schema. The only question is whether it lives in the database, where it is enforced, or only in your head, where it is not.
Here is what that costs in practice. Suppose one part of your code writes email and another part, written six months later by someone in a hurry, writes emial. A relational database would reject the second insert outright because there is no such column. MongoDB accepts it without a murmur. Nothing breaks today. It breaks the week you run a report and a third of your users appear to have no email address at all.
The real value of flexibility is evolution. You can add a referredBy field to new users next month without rewriting the two lakh documents already stored, and your code can treat the field as optional. That is a genuine advantage over altering a large SQL table. It is not permission to let every document invent its own shape.
// MongoDB allows all three of these in one collection
db.users.insertMany([
{ name: "Ananya", email: "ananya@example.com", age: 22 },
{ name: "Rahul", email: "rahul@example.com" }, // no age
{ name: "Meera", emial: "meera@example.com", city: "Kochi" } // typo, accepted!
])
// The typo only shows up later, as a silently wrong result
db.users.countDocuments({ email: { $exists: true } }) // 2, not 3 - Two later lessons fix exactly this problem: Schema Validation shows how to make the database itself reject a bad document, and Mongoose ODM shows how to enforce a shape from your Node.js code.
When MongoDB Fits, and When It Does Not
No database is right for everything, and choosing one because it is fashionable is how projects get rewritten. MongoDB is at its best when your data naturally arrives as whole objects that you read and write together — a product with a variable list of attributes, an order with its line items, a user with their preferences and addresses.
It is a weaker fit when nearly every query in your application pulls small pieces from five different places and combines them, or when you need the database itself to guarantee relationships between tables. MongoDB can do joins with $lookup and it does support transactions, but neither is as effortless as in a relational engine built around them.
- Good fit: catalogues where different products have different attributes
- Good fit: data that is written and read as one whole object, such as an order and its items
- Good fit: projects whose requirements are still moving and whose fields keep changing
- Good fit: applications that expect to outgrow a single database server
- Weaker fit: reporting workloads that are mostly multi-table joins and ad-hoc SQL
- Weaker fit: systems that must have foreign keys and cross-table constraints enforced by the database itself
- "NoSQL means no transactions" is an outdated claim. MongoDB has supported multi-document transactions since version 4.0, and a later lesson in this course uses them. Choose MongoDB for the shape of your data, not because you were told it is faster.
