How to Perform JOIN Operation in MongoDB

MongoDB is a NoSQL database, so it does not use the traditional SQL JOIN statement. However, MongoDB provides the $lookup aggregation stage to perform a join between two collections.

1. Basic Syntax of $lookup

db.collection1.aggregate([
    {
        $lookup: {
            from: "collection2",
            localField: "field1",
            foreignField: "field2",
            as: "result"
        }
    }
])

Meaning of fields

FieldMeaning
fromCollection to join
localFieldField from the current collection
foreignFieldMatching field from the other collection
asName of the resulting array

2. Example: Student and Department

Suppose we have two collections:

students

db.students.insertMany([
    { _id: 1, name: "Rahul", dept_id: 101 },
    { _id: 2, name: "Priya", dept_id: 102 },
    { _id: 3, name: "Amit", dept_id: 101 }
])

departments

db.departments.insertMany([
    { _id: 101, dept_name: "Computer Science" },
    { _id: 102, dept_name: "Information Technology" }
])

3. Perform JOIN using $lookup

db.students.aggregate([
    {
        $lookup: {
            from: "departments",
            localField: "dept_id",
            foreignField: "_id",
            as: "department"
        }
    }
])

Output

[
    {
        _id: 1,
        name: "Rahul",
        dept_id: 101,
        department: [
            {
                _id: 101,
                dept_name: "Computer Science"
            }
        ]
    },
    {
        _id: 2,
        name: "Priya",
        dept_id: 102,
        department: [
            {
                _id: 102,
                dept_name: "Information Technology"
            }
        ]
    }
]

The department field contains the matching documents from the departments collection.


4. $lookup with $unwind

Because $lookup normally returns the matching records as an array, we can use $unwind to convert it into an individual object.

db.students.aggregate([
    {
        $lookup: {
            from: "departments",
            localField: "dept_id",
            foreignField: "_id",
            as: "department"
        }
    },
    {
        $unwind: "$department"
    }
])

Result

{
    _id: 1,
    name: "Rahul",
    dept_id: 101,
    department: {
        _id: 101,
        dept_name: "Computer Science"
    }
}

5. Display Only Required Fields

We can use $project after $lookup.

db.students.aggregate([
    {
        $lookup: {
            from: "departments",
            localField: "dept_id",
            foreignField: "_id",
            as: "department"
        }
    },
    {
        $unwind: "$department"
    },
    {
        $project: {
            _id: 0,
            name: 1,
            "department.dept_name": 1
        }
    }
])

Output

{
    name: "Rahul",
    department: {
        dept_name: "Computer Science"
    }
}

6. SQL JOIN vs MongoDB $lookup

SQLMongoDB
JOIN$lookup
ONlocalField + foreignField
SELECT$project
WHERE$match
Multiple rowsArray of matching documents
GROUP BY$group

SQL Example

SELECT students.name, departments.dept_name
FROM students
JOIN departments
ON students.dept_id = departments.id;

MongoDB Equivalent

db.students.aggregate([
    {
        $lookup: {
            from: "departments",
            localField: "dept_id",
            foreignField: "_id",
            as: "department"
        }
    },
    {
        $unwind: "$department"
    },
    {
        $project: {
            name: 1,
            "department.dept_name": 1
        }
    }
])

Important point for exams

MongoDB performs JOIN-like operations using the $lookup stage of the aggregation pipeline. $lookup matches documents from one collection with documents from another collection based on specified fields.

Short answer:
$lookup in MongoDB is mainly used to perform a JOIN operation between collections.

The important point is: $unwind works on arrays, not ordinary objects. An object itself is not “unwound.”

1. Array

An array contains multiple values:

{
    name: "Rahul",
    subjects: ["MongoDB", "PHP", "Python"]
}

Using:

db.students.aggregate([
    { $unwind: "$subjects" }
])

produces 3 documents:

{ name: "Rahul", subjects: "MongoDB" }
{ name: "Rahul", subjects: "PHP" }
{ name: "Rahul", subjects: "Python" }

So:

Array → $unwind → multiple documents


2. Object

An object contains key-value pairs:

{
    name: "Rahul",
    address: {
        city: "Rajkot",
        state: "Gujarat"
    }
}

Here, address is an object, not an array.

You do not use $unwind on it:

{ $unwind: "$address" }   // Not useful

You can directly access its fields:

db.students.find(
    {},
    {
        name: 1,
        "address.city": 1
    }
)

Result:

{
    name: "Rahul",
    address: {
        city: "Rajkot"
    }
}

Array vs Object

FeatureArrayObject
ContainsMultiple values/elementsKey-value pairs
Example["PHP", "MongoDB"]{city:"Rajkot", state:"Gujarat"}
$unwind✅ Used❌ Not normally used
Result of $unwindOne document per array elementNo decomposition
Access$subjects$address.city

Very important for $lookup

$lookup normally produces an array:

course: [
    {
        _id: 101,
        course_name: "BCA"
    }
]

Therefore, we often write:

{
    $unwind: "$course"
}

After $unwind:

course: {
    _id: 101,
    course_name: "BCA"
}

So remember:

Array = collection of elements → $unwind can separate them.
Object = one structured value → access its fields directly.

By admin