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
| Command | Purpose |
|---|---|
find() | Returns documents |
distinct() | Returns unique values |
countDocuments() | Counts matching documents |
aggregate() + $group | Can 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
| Command | Purpose |
|---|---|
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 field0= 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
| Operator | Meaning | Example |
|---|---|---|
$sum | Adds values / counts | { $sum: "$salary" } |
$avg | Calculates average | { $avg: "$salary" } |
$max | Finds maximum | { $max: "$salary" } |
$min | Finds minimum | { $min: "$salary" } |
$push | Adds 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
| Operator | Purpose | Example |
|---|---|---|
$sum | Total / count | { $sum: "$amount" } |
$avg | Average | { $avg: "$amount" } |
$max | Maximum | { $max: "$amount" } |
$min | Minimum | { $min: "$amount" } |
$push | Create array | { $push: "$cust_id" } |
Aggregation Stage Summary
| Stage | Purpose | SQL Equivalent |
|---|---|---|
$match | Filter documents | WHERE |
$project | Select fields | SELECT |
$group | Group & calculate | GROUP BY |
$sort | Sort documents | ORDER BY |
$skip | Skip documents | OFFSET |
$limit | Limit documents | LIMIT |
$unwind | Expand 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.