Quick Answer

find() is SELECT, the first argument is WHERE and the second chooses columns. Operators like $gt and $in replace SQL comparison syntax. The real difference is that documents can be nested, so related data is often embedded rather than joined.

The vocabulary maps almost directly

  • Table becomes collection
  • Row becomes document
  • Column becomes field
  • Primary key becomes _id, generated automatically if you do not supply one

A document is JSON-like, so a student record can hold an array of marks and a nested address object directly — no separate tables required. That single capability drives most of the design differences.

{
  _id: ObjectId("..."),
  name: "Asha",
  stream: "Science",
  marks: 91,
  address: { city: "Pune", pin: "411001" }
}

There is also no enforced schema by default. Two documents in one collection can have different fields, which is flexible and dangerous in equal measure — see the last section.

find() is SELECT

// SELECT * FROM student
db.student.find({})

// SELECT * FROM student WHERE stream = 'Science'
db.student.find({ stream: "Science" })

// SELECT name, marks FROM student WHERE stream = 'Science'
db.student.find({ stream: "Science" }, { name: 1, marks: 1, _id: 0 })

The first argument is the filter, the second chooses which fields to return. In that second object, 1 includes and 0 excludes — and _id is returned unless you explicitly switch it off, which surprises people the first time.

Add ordering and limits by chaining:

db.student.find({}).sort({ marks: -1 }).limit(2)
// ORDER BY marks DESC LIMIT 2

-1 is descending, 1 ascending.

Operators replace comparison syntax

Since the filter is an object, comparisons need named operators:

db.student.find({ marks: { $gt: 80 } })          // marks > 80
db.student.find({ marks: { $gte: 80, $lt: 95 } }) // BETWEEN-ish
db.student.find({ stream: { $in: ["Science", "Arts"] } })  // IN
db.student.find({ stream: { $ne: "Commerce" } })  // !=

Combining conditions: listing several fields in one object is an implicit AND. For OR you need it explicitly:

db.student.find({ $or: [ { marks: { $gt: 90 } },
                         { stream: "Arts" } ] })

Querying inside nested documents and arrays uses dot notation, and it works for both:

db.student.find({ "address.city": "Pune" })

If marks were an array, { marks: 91 } matches any document whose array contains 91. That behaviour is convenient and occasionally surprising.

Aggregation is GROUP BY

The aggregation pipeline runs documents through stages, each transforming the output of the last:

db.student.aggregate([
  { $match: { marks: { $gt: 60 } } },
  { $group: { _id: "$stream", avg: { $avg: "$marks" } } },
  { $sort: { avg: -1 } }
])

That is WHERE, then GROUP BY, then ORDER BY. In $group, _id is what you are grouping by, and $stream with the dollar prefix means "the value of the stream field".

Put $match as early as possible. Filtering before grouping means later stages handle fewer documents, and it lets an index do the work — the same reasoning as indexing in SQL.

What is genuinely different

Embedding versus joining. In SQL you normalize and join. In MongoDB you often embed related data inside the parent document, so reading it is a single lookup. That is faster to read and duplicates data, which brings back the update problem normalization exists to prevent. The usual guidance is to embed data that is read together and owned by the parent, and reference data that is shared or grows without limit.

No enforced schema by default. Two documents can have different fields, so an application bug can write mark instead of marks and nothing complains. Queries then silently miss those documents. Use schema validation, or a layer like Mongoose, to get that safety back.

Joins exist but are secondary. $lookup performs a join in an aggregation pipeline. It works, but if your data model needs it everywhere, that is a signal a relational database may suit the problem better.

Frequently Asked Questions

Is MongoDB better than SQL? Neither is better in general. MongoDB suits flexible or nested documents and rapid schema change; relational databases suit data with many relationships and strong consistency requirements. Choose by the shape of the data, not by preference.
Does MongoDB support joins? Yes, through $lookup in an aggregation pipeline. It is less central than in SQL, because the usual approach is to embed related data. Needing joins everywhere suggests a relational database may fit better.
What is _id? The primary key of a document, generated automatically as an ObjectId if you do not supply one. It is unique within the collection and is returned by queries unless you explicitly exclude it.
Should I embed or reference related data? Embed when the data is read together and belongs to the parent, such as an address on a user. Reference when it is shared between documents or grows without bound, such as a user's activity log.
Do I need to define a schema? Not by default, but you should. Without validation, a typo in a field name silently creates a different field and queries quietly miss those documents. Use MongoDB schema validation or an ODM such as Mongoose.