MongoDB distinct() Operator & MongoDB aggregate()

MongoDB distinct() Operator

In MongoDB, distinct() is used to find unique values of a particular field from a collection. It returns the unique values in an array.

Syntax

db.collection.distinct("fieldName")

Example: Employee Collection

Suppose emp contains:

{ empno: 1, ename: "Amit",   dept: "IT",    salary: 25000 }
{ empno: 2, ename: "Ravi",   dept: "HR",    salary: 30000 }
{ empno: 3, ename: "Neha",   dept: "IT",    salary: 28000 }
{ empno: 4, ename: "Raj",    dept: "Sales", salary: 35000 }
{ empno: 5, ename: "Priya",  dept: "HR",    salary: 32000 }

1. Find distinct departments

db.emp.distinct("dept")

Output:

[ "IT", "HR", "Sales" ]

Even though IT and HR occur multiple times, they are returned only once.


2. Find distinct employee names

db.emp.distinct("ename")

Output:

[ "Amit", "Ravi", "Neha", "Raj", "Priya" ]

3. Distinct with a condition

You can provide a query as the second argument. MongoDB’s syntax is:

db.collection.distinct("field", { condition })

For example, find distinct departments where salary is greater than 28000:

db.emp.distinct("dept", { salary: { $gt: 28000 } })

Output:

[ "HR", "Sales" ]

4. Distinct values of salary

db.emp.distinct("salary")

Output:

[ 25000, 30000, 28000, 35000, 32000 ]

5. Distinct values from an array

If documents contain:

{ name: "A", skills: ["Java", "MongoDB"] }
{ name: "B", skills: ["Python", "MongoDB"] }
{ name: "C", skills: ["Java", "PHP"] }

Then:

db.student.distinct("skills")

returns:

[ "Java", "MongoDB", "Python", "PHP" ]

MongoDB treats array elements as individual values for distinct().

⭐ Important Difference

CommandPurpose
find()Returns documents
distinct()Returns unique values
countDocuments()Counts matching documents
aggregate() + $groupCan group and calculate results

Simple rule:

distinct() = “Give me only the unique values of this field.”

MongoDB distinct() official documentation

db.emp.createIndex({empno:1}) db.emp.ensureIndex({empno:1}) db.emp.getIndexes() db.emp.dropIndex({empno:1})

These are MongoDB Index commands. Here is what each command does:

1. createIndex()

db.emp.createIndex({ empno: 1 })

Creates an index on the empno field.

  • 1 → Ascending order
  • -1 → Descending order

Example:

db.emp.createIndex({ empno: 1 })

Output may be:

{
  "name": "empno_1",
  "key": { "empno": 1 }
}

The index can make queries such as this faster:

db.emp.find({ empno: 10 })

2. ensureIndex()

db.emp.ensureIndex({ empno: 1 })

ensureIndex() was an older MongoDB method used to create an index if it did not already exist.

For modern MongoDB versions, use:

db.emp.createIndex({ empno: 1 })

So for teaching/current MongoDB:

Prefer createIndex() over ensureIndex().


3. getIndexes()

db.emp.getIndexes()

Displays all indexes available on the emp collection.

For example:

[
  {
    name: "_id_",
    key: { _id: 1 }
  },
  {
    name: "empno_1",
    key: { empno: 1 }
  }
]

The _id_ index is automatically created by MongoDB.


4. dropIndex()

db.emp.dropIndex({ empno: 1 })

Deletes the index on empno.

You can also delete it using its name:

db.emp.dropIndex("empno_1")

After deleting:

db.emp.getIndexes()

you will normally see only:

[
  {
    name: "_id_",
    key: { _id: 1 }
  }
]

Quick Summary

CommandPurpose
createIndex()Create an index
ensureIndex()Older method for creating an index
getIndexes()Display all indexes
dropIndex()Delete an index

Example complete sequence:

// Create index
db.emp.createIndex({ empno: 1 })

// View indexes
db.emp.getIndexes()

// Delete index
db.emp.dropIndex({ empno: 1 })

// View again
db.emp.getIndexes()

Remember: 1 = ascending, -1 = descending.

(1) $ project – It is used to select some specific field from a collection.

(2) $ match – This is filtering operation for reduce the amount of document which will be given as input to the next stage.

(3) $group – It is used for simple count operations where the actual aggregation done.

(4) $sort – It is used to sort the documents.

(5) $skip – It is used to skip the documents from given amount of documents.

(6) $ limit – It is used to limit the amount of documents by the given number starting from current position.

(7) $ unwind – It is used to unwind the document data using array. This operation will be undone the joint data and keep the documents individual. It will increase the amount of documents for the next stage.

use geet1

db.createCollection(’emp’)

db.emp.insert({’empno’:001,’empnm’:’mital’,’salary’:5000})

db.emp.insert({’empno’:002, ’empnm’:’sheetal’,’salary’:6000})

db.emp.insert({’empno’:003, ’empnm’:’neha’,’salary’:7000})

//sum of all salary

db.emp.aggregate([{$group : {_id : null, salary_sum : {$sum : ‘$salary’}}}])

//select empnm, sum(salary) salary_sum from emp where salary > 5000 group by firstName

db.emp.aggregate([ { $match: { salary : { $gt: 5000} } }, {$group : {_id : “$empnm”, salary_sum : {$sum : “$salary”}}}])

//count record whose salary is >5000 using aggregate function.

db.emp.aggregate([ {$match:{salary:{$gt:5000}}}, {$group:{_id:null,count:{$sum:1}}} ])

use geet

db.createCollection(‘student’);

var students =

[

{ rollNo:1, name:”Ganesh”, city:”Rajkot”, state:”Gujarat”, mobileNo:”9999999999″, result:”PASS”, percentage:86 },

{ rollNo:2, name:”Shankar”, city:”Ahmedabad”, state:”Gujarat”, mobileNo:”9999999998″, result:”PASS”, percentage:80 },

{ rollNo:3, name:”Mahadev”, city:”Mumbai”, state:”Maharashtra”, mobileNo:”88888888888″, result:”PASS”, percentage:89 },

{ rollNo:4, name:”Rajesh”, city:”Nashik”, state:”Maharashtra”, mobileNo:”9999957699″, result:”PASS”, percentage:56 },

{ rollNo:5, name:”Samay”, city:”Jaipur”, state:”Rajasthan”, mobileNo:”8888999999″, result:”FAIL”, percentage:33 },

];

db.student.insert(students)

db.student.find()

db.student.find({city:”Rajkot”}).pretty();

db.student.aggregate({ $match:{city:”Rajkot”}}).pretty();

db.student.find({percentage:{$lt:60}}).pretty();

db.student.aggregate({$match:{percentage:{$lt:60}}}).pretty();

db.student.find({city:{$ne:”Rajkot”}}).pretty();

db.student.aggregate({$match:{city:{$ne:”Rajkot”}}}).pretty();

db.student.count({percentage:{$lt:60}})

db.student.find({percentage:{$lt:60}}).count();

db.student.find({city:”Rajkot”}).count();

db.student.find({city:”Rajkot”}).count();

//state vise max percentage

db.student.aggregate( { $group:{_id:”$state”, minPercentage:{$max:”$percentage”}} } );

//maximum persentage

db.student.aggregate({$group:{_id:”rollNo”,”percentage”:{$max:”$percentage”}}})

db.student.aggregate({$match:{city:”Rajkot”}}).pretty();

db.student.aggregate({$match:{percentage:{$lt:60}}}).pretty();

db.student.aggregate({$match:{city:{$ne:”Rajkot”}}}).pretty();

db.student.count({city:”Rajkot”}); db.student.find({city:”Rajkot”}).count();

db.student.aggregate({$sort:{percentage:1}}) db.student.aggregate({$sort:{percentage:-1}})

db.student.aggregate({$sort:{percentage:-1}},{$skip:2})

db.student.aggregate({$sort:{percentage:-1}},{$skip:2},{$limit:2})

use geet1

db.createCollection(’emp’)

db.emp.insert({’empno’:001,’empnm’:’mital’,’salary’:5000})

db.emp.insert({’empno’:002, ’empnm’:’sheetal’,’salary’:6000})

db.emp.insert({’empno’:003, ’empnm’:’neha’,’salary’:7000})

//select record

db.emp.aggregate([{$project: { _id:0, ename:1, salary:1}}])

//display id

db.emp.aggregate([{$project: { _id:1, ename:1, salary:1}}])

Your notes cover the MongoDB Aggregation Framework. A few points need correction, especially the $group, $limit, $unwind, and maximum-percentage examples.

MongoDB Aggregation Pipeline

An aggregation pipeline processes documents through multiple stages.

db.collection.aggregate([
    { stage1 },
    { stage2 },
    { stage3 }
])

1. $project — Select fields

Used to include or exclude specific fields.

db.emp.aggregate([
    { $project: { _id: 0, empnm: 1, salary: 1 } }
])

Output:

{ empnm: "mital", salary: 5000 }
{ empnm: "sheetal", salary: 6000 }
{ empnm: "neha", salary: 7000 }

1 = include field
0 = exclude field


2. $match — Filter documents

Works like the WHERE clause in SQL.

db.emp.aggregate([
    { $match: { salary: { $gt: 5000 } } }
])

This returns employees whose salary is greater than 5000.

SQL equivalent:

SELECT * FROM emp
WHERE salary > 5000;

3. $group — Group and calculate

Used to group documents and perform calculations such as $sum, $avg, $min, and $max.

db.emp.aggregate([
    {
        $group: {
            _id: null,
            salary_sum: { $sum: "$salary" }
        }
    }
])

Result:

{ _id: null, salary_sum: 18000 }

Count records

db.emp.aggregate([
    {
        $group: {
            _id: null,
            count: { $sum: 1 }
        }
    }
])

4. $sort — Sort documents

db.student.aggregate([
    { $sort: { percentage: 1 } }
])

1 = ascending

db.student.aggregate([
    { $sort: { percentage: -1 } }
])

-1 = descending


5. $skip — Skip documents

db.student.aggregate([
    { $sort: { percentage: -1 } },
    { $skip: 2 }
])

First 2 documents are skipped.


6. $limit — Limit documents

db.student.aggregate([
    { $sort: { percentage: -1 } },
    { $limit: 2 }
])

Returns only the first 2 documents after the preceding stage.

For example, pagination:

db.student.aggregate([
    { $sort: { percentage: -1 } },
    { $skip: 2 },
    { $limit: 2 }
])

This skips 2 and then returns the next 2.


7. $unwind — Expand array elements

Suppose:

{
    name: "Mital",
    skills: ["MongoDB", "Java", "Python"]
}

Query:

db.student.aggregate([
    { $unwind: "$skills" }
])

Result:

{ name: "Mital", skills: "MongoDB" }
{ name: "Mital", skills: "Java" }
{ name: "Mital", skills: "Python" }

So $unwind converts one document containing an array into multiple documents.


Your emp Example

use geet1

db.createCollection("emp")

db.emp.insertMany([
    { empno: 1, empnm: "mital", salary: 5000 },
    { empno: 2, empnm: "sheetal", salary: 6000 },
    { empno: 3, empnm: "neha", salary: 7000 }
])

Sum of all salaries

db.emp.aggregate([
    {
        $group: {
            _id: null,
            salary_sum: { $sum: "$salary" }
        }
    }
])

Result:

salary_sum = 18000

Employees with salary > 5000

db.emp.aggregate([
    { $match: { salary: { $gt: 5000 } } }
])

Sum salary after filtering

db.emp.aggregate([
    { $match: { salary: { $gt: 5000 } } },
    {
        $group: {
            _id: null,
            salary_sum: { $sum: "$salary" }
        }
    }
])

Result:

salary_sum = 13000

Count salary > 5000

db.emp.aggregate([
    { $match: { salary: { $gt: 5000 } } },
    {
        $group: {
            _id: null,
            count: { $sum: 1 }
        }
    }
])

Result:

count = 2

Student Examples

Your student data can be used to demonstrate almost every aggregation stage.

Students from Rajkot

db.student.aggregate([
    { $match: { city: "Rajkot" } }
])

Percentage less than 60

db.student.aggregate([
    { $match: { percentage: { $lt: 60 } } }
])

City is not Rajkot

db.student.aggregate([
    { $match: { city: { $ne: "Rajkot" } } }
])

Sort percentage ascending

db.student.aggregate([
    { $sort: { percentage: 1 } }
])

Sort percentage descending

db.student.aggregate([
    { $sort: { percentage: -1 } }
])

Top 2 students

db.student.aggregate([
    { $sort: { percentage: -1 } },
    { $limit: 2 }
])

Important Correction: State-wise Maximum Percentage

You wrote:

db.student.aggregate(
    {
        $group: {
            _id: "$state",
            minPercentage: { $max: "$percentage" }
        }
    }
)

The calculation is $max, so the field should be named maxPercentage:

db.student.aggregate([
    {
        $group: {
            _id: "$state",
            maxPercentage: { $max: "$percentage" }
        }
    }
])

Expected result:

Gujarat      → 86
Maharashtra  → 89
Rajasthan    → 33

Important Correction: Maximum Percentage Overall

You wrote:

db.student.aggregate({
    $group: {
        _id: "rollNo",
        percentage: { $max: "$percentage" }
    }
})

"rollNo" is a literal string, not the field reference.

For overall maximum percentage, use:

db.student.aggregate([
    {
        $group: {
            _id: null,
            maxPercentage: { $max: "$percentage" }
        }
    }
])

Result:

maxPercentage: 89

For maximum percentage for each roll number, use:

db.student.aggregate([
    {
        $group: {
            _id: "$rollNo",
            maxPercentage: { $max: "$percentage" }
        }
    }
])

$group Accumulator Operators

OperatorMeaningExample
$sumAdds values / counts{ $sum: "$salary" }
$avgCalculates average{ $avg: "$salary" }
$maxFinds maximum{ $max: "$salary" }
$minFinds minimum{ $min: "$salary" }
$pushAdds values into an array{ $push: "$empnm" }

Example: Average salary

db.emp.aggregate([
    {
        $group: {
            _id: null,
            averageSalary: { $avg: "$salary" }
        }
    }
])

Example: Minimum salary

db.emp.aggregate([
    {
        $group: {
            _id: null,
            minSalary: { $min: "$salary" }
        }
    }
])

Example: Maximum salary

db.emp.aggregate([
    {
        $group: {
            _id: null,
            maxSalary: { $max: "$salary" }
        }
    }
])

Example: Group employees by state

db.student.aggregate([
    {
        $group: {
            _id: "$state",
            students: { $push: "$name" }
        }
    }
])

This produces one document per state with an array of student names.

Easy way to remember

$match   → WHERE
$project → SELECT fields
$group   → GROUP BY + calculations
$sort    → ORDER BY
$skip    → SKIP
$limit   → LIMIT
$unwind  → Expand array

MongoDB aggregation practical in a clean proper format, with corrections to a few queries.

1. Create Database and Insert Records

use product

db.orders.insertMany([
    {
        _id: 1,
        cust_id: "abc1",
        ord_date: ISODate("2012-11-02T17:04:11.102Z"),
        status: "A",
        amount: 50
    },
    {
        _id: 2,
        cust_id: "xyz1",
        ord_date: ISODate("2013-10-01T17:04:11.102Z"),
        status: "A",
        amount: 100
    },
    {
        _id: 3,
        cust_id: "xyz1",
        ord_date: ISODate("2013-10-12T17:04:11.102Z"),
        status: "D",
        amount: 25
    },
    {
        _id: 4,
        cust_id: "xyz1",
        ord_date: ISODate("2013-10-11T17:04:11.102Z"),
        status: "D",
        amount: 125
    },
    {
        _id: 5,
        cust_id: "abc1",
        ord_date: ISODate("2013-11-12T17:04:11.102Z"),
        status: "A",
        amount: 25
    }
])

2. Display All Orders

db.orders.aggregate([
    { $match: {} }
])

Or simply:

db.orders.find()

3. Find Orders with Status "A"

db.orders.aggregate([
    { $match: { status: "A" } }
])

Result

abc1 → 50
xyz1 → 100
abc1 → 25

4. Group by Customer and Calculate Sum

Question:

Find the total amount for each customer where status is "A".

db.orders.aggregate([
    { $match: { status: "A" } },
    {
        $group: {
            _id: "$cust_id",
            total: { $sum: "$amount" }
        }
    }
])

Result

abc1 → 75
xyz1 → 100

5. Group by Customer, Sum and Sort

db.orders.aggregate([
    { $match: { status: "A" } },
    {
        $group: {
            _id: "$cust_id",
            total: { $sum: "$amount" }
        }
    },
    { $sort: { total: -1 } }
])

Meaning

$match  → Filter status A
$group  → Group by cust_id
$sum    → Calculate total amount
$sort   → Sort total in descending order

6. explain() with Aggregation

db.orders.explain().aggregate([
    { $match: { status: "A" } },
    {
        $group: {
            _id: "$cust_id",
            total: { $sum: "$amount" }
        }
    },
    { $sort: { total: -1 } }
])

explain() is used to examine how MongoDB executes the query.


7. $match with Amount Greater Than 100

db.orders.aggregate([
    {
        $match: {
            amount: { $gt: 100 }
        }
    }
])

Result

_id: 4
cust_id: xyz1
amount: 125

8. $project — Select Specific Fields

db.orders.aggregate([
    {
        $project: {
            _id: 0,
            cust_id: 1,
            ord_date: 1,
            amount: 1
        }
    }
])

This displays:

cust_id
ord_date
amount

and hides _id.


9. $project — Display Only Customer and Amount

db.orders.aggregate([
    {
        $project: {
            _id: 0,
            cust_id: 1,
            amount: 1
        }
    }
])

10. $sort — Amount Ascending

db.orders.aggregate([
    { $sort: { amount: 1 } }
])

Result order:

25
25
50
100
125

11. $sort — Amount Descending

db.orders.aggregate([
    { $sort: { amount: -1 } }
])

Result order:

125
100
50
25
25

12. $limit — First 2 Documents

db.orders.aggregate([
    { $limit: 2 }
])

Returns only 2 documents.


13. $skip — Skip 2 Documents

db.orders.aggregate([
    { $skip: 2 }
])

Skips the first 2 documents.


14. $skip + $limit

db.orders.aggregate([
    { $skip: 2 },
    { $limit: 2 }
])

Meaning:

Skip first 2
      ↓
Take next 2

15. Average Amount by Status

db.orders.aggregate([
    {
        $group: {
            _id: "$status",
            averageamount: { $avg: "$amount" }
        }
    }
])

Calculation

For status A:

50 + 100 + 25 = 175
175 / 3 = 58.33

For status D:

25 + 125 = 150
150 / 2 = 75

16. Minimum Amount by Status

db.orders.aggregate([
    {
        $group: {
            _id: "$status",
            minamount: { $min: "$amount" }
        }
    }
])

Result

A → 25
D → 25

17. Maximum Amount by Status

db.orders.aggregate([
    {
        $group: {
            _id: "$status",
            maxamount: { $max: "$amount" }
        }
    }
])

Result:

A → 100
D → 125

18. Sum Amount by Status

db.orders.aggregate([
    {
        $group: {
            _id: "$status",
            totalamount: { $sum: "$amount" }
        }
    }
])

Result:

A → 175
D → 150

19. Count Orders by Status

db.orders.aggregate([
    {
        $group: {
            _id: "$status",
            count: { $sum: 1 }
        }
    }
])

Result:

A → 3
D → 2

20. $in Operator

Find orders whose status is either A or B:

db.orders.aggregate([
    {
        $match: {
            status: { $in: ["A", "B"] }
        }
    }
])

Since our data has only A and D, only A records are returned.


21. Customer abc1 OR xyz1

Your original query was:

{ $match: { cust_id: "abc1", cust_id: "xyz1" } }

❌ This is incorrect because the same field cannot simultaneously equal "abc1" and "xyz1".

Use $in:

db.orders.aggregate([
    {
        $match: {
            cust_id: { $in: ["abc1", "xyz1"] }
        }
    }
])

This returns both customers.


22. Customer abc1 Only

db.orders.aggregate([
    {
        $match: {
            cust_id: "abc1"
        }
    }
])

23. Group by Customer and Calculate Average

db.orders.aggregate([
    {
        $group: {
            _id: "$cust_id",
            averageAmount: { $avg: "$amount" }
        }
    }
])

24. Group by Customer and Find Maximum

db.orders.aggregate([
    {
        $group: {
            _id: "$cust_id",
            maxAmount: { $max: "$amount" }
        }
    }
])

25. Complete Aggregation Example

Question:

Find total order amount for status A, group by customer, and display highest total first.

db.orders.aggregate([
    {
        $match: {
            status: "A"
        }
    },
    {
        $group: {
            _id: "$cust_id",
            totalAmount: { $sum: "$amount" }
        }
    },
    {
        $sort: {
            totalAmount: -1
        }
    }
])

Output

{ _id: "xyz1", totalAmount: 100 }
{ _id: "abc1", totalAmount: 75 }

Important $group Operators

OperatorPurposeExample
$sumTotal / count{ $sum: "$amount" }
$avgAverage{ $avg: "$amount" }
$maxMaximum{ $max: "$amount" }
$minMinimum{ $min: "$amount" }
$pushCreate array{ $push: "$cust_id" }

Aggregation Stage Summary

StagePurposeSQL Equivalent
$matchFilter documentsWHERE
$projectSelect fieldsSELECT
$groupGroup & calculateGROUP BY
$sortSort documentsORDER BY
$skipSkip documentsOFFSET
$limitLimit documentsLIMIT
$unwindExpand array—

Best pattern to teach students:

db.orders.aggregate([
    { $match: { ... } },
    { $project: { ... } },
    { $group: { ... } },
    { $sort: { ... } },
    { $skip: ... },
    { $limit: ... }
])

Not every query needs every stage; the stages are executed from top to bottom.

By admin