$group: การรวมข้อมูลและการคำนวณยอดรวม
ผู้เรียนจะจัดกลุ่มเอกสารตามคีย์ และคำนวณผลรวม ค่าเฉลี่ย จำนวน และค่ารวมประเภทอื่น ๆ ด้วย $group
$group: การรวมข้อมูลและการคำนวณยอดรวม เป็นบทเรียน MongoDB Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน MongoDB Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
What Does $group Do?
The $group stage collapses multiple input documents into fewer output documents based on a grouping key. Documents that share the same key value are merged into a single output document, and accumulator operators compute aggregate values for each group. Think of it as MongoDB's equivalent of SQL's GROUP BY clause combined with aggregate functions like SUM and COUNT.
// Count orders per user
db.orders.aggregate([
{ $group: {
_id: '$userId', // group by userId
orderCount: { $sum: 1 } // count each document as 1
}}
]);
// Output: one doc per unique userId with their order countThe _id Field in $group
Every $group stage requires an _id field that defines the grouping key. The _id can be a field reference ('$field'), a computed expression, an object with multiple fields (for compound grouping), or null (to aggregate the entire collection into one document). The _id value in the output is the group key.
// Group by single field
{ $group: { _id: '$status' } }
// Group by multiple fields (compound key)
{ $group: { _id: { year: { $year: '$createdAt' }, status: '$status' } } }
// Group all documents into one (grand total)
{ $group: { _id: null, grandTotal: { $sum: '$amount' } } }
// Group by computed expression
{ $group: { _id: { $toLower: '$category' } } }$sum: Counting and Summing
$sum is the most used accumulator. Pass 1 to count documents in each group, or a field reference to sum numeric field values. You can also pass an expression that evaluates to a number. $sum ignores non-numeric values and missing fields (they count as zero), making it safe to use on optional numeric fields.
db.sales.aggregate([{
$group: {
_id: '$region',
// Count documents in each group
transactionCount: { $sum: 1 },
// Sum the 'amount' field
totalRevenue: { $sum: '$amount' },
// Sum a computed expression
totalWithTax: { $sum: { $multiply: ['$amount', 1.1] } }
}
}]);$avg, $min, $max
$avg computes the arithmetic mean, $min finds the smallest value, and $max finds the largest value across all documents in a group. All three work on numeric values and also on strings and dates (for min/max). They ignore null and missing field values.
db.orders.aggregate([{
$group: {
_id: '$productId',
avgRating: { $avg: '$rating' }, // average rating
minPrice: { $min: '$price' }, // lowest price ever sold
maxPrice: { $max: '$price' }, // highest price ever sold
firstOrder: { $min: '$createdAt' }, // earliest date
latestOrder: { $max: '$createdAt' } // most recent date
}
}]);$count in $group
While you typically count by using { $sum: 1 } in a $group stage, MongoDB also provides a standalone $count stage to count the total number of documents in the stream. The $count stage emits a single document with the count under the field name you specify. It's equivalent to a $group with _id: null and a $sum: 1.
// Count total published articles
db.articles.aggregate([
{ $match: { status: 'published' } },
{ $count: 'totalPublished' } // emits { totalPublished: N }
]);
// Equivalent using $group:
db.articles.aggregate([
{ $match: { status: 'published' } },
{ $group: { _id: null, totalPublished: { $sum: 1 } } }
]);Compound Grouping Keys
To group by multiple fields simultaneously, pass an object as the _id value. Each key in the object becomes part of the compound group key. The output documents have a nested _id object. This is the standard way to produce multi-dimensional aggregations like 'revenue by region and month'.
// Revenue breakdown by region AND year-month
db.sales.aggregate([
{ $group: {
_id: {
region: '$region',
year: { $year: '$saleDate' },
month: { $month: '$saleDate' }
},
revenue: { $sum: '$amount' },
count: { $sum: 1 }
}},
{ $sort: { '_id.year': 1, '_id.month': 1, '_id.region': 1 } }
]);
// Output: { _id: { region: 'EMEA', year: 2024, month: 3 }, revenue: 50000, count: 120 }Accumulating Into Arrays With $push
The $push accumulator collects all values from a field across the grouped documents into an array. This is useful for gathering all order IDs under a user, all tags under a category, or all user IDs who purchased a product. The result array can contain duplicates; use $addToSet instead to collect unique values.
// Collect all order IDs per user
db.orders.aggregate([{
$group: {
_id: '$userId',
orderIds: { $push: '$_id' }, // all order IDs for this user
amounts: { $push: '$amount' }, // all amounts
// Collect whole sub-documents
orderSummaries: {
$push: { orderId: '$_id', amount: '$amount', status: '$status' }
}
}
}]);$first and $last Accumulators
$first and $last return the first and last field value encountered per group, in the order documents are processed. Because MongoDB does not guarantee document order unless you sort first, you should add a $sort stage before the $group stage to make $first/$last meaningful—for example, 'first order date per customer'.
// Most and least recent order per customer
db.orders.aggregate([
{ $sort: { createdAt: 1 } }, // sort BEFORE group for meaningful first/last
{ $group: {
_id: '$customerId',
firstOrder: { $first: '$createdAt' },
firstOrderId: { $first: '$_id' },
lastOrder: { $last: '$createdAt' },
lastAmount: { $last: '$amount' }
}}
]);Grouping on Computed Expressions
The $group _id can be any expression, not just a field reference. You can group by a truncated date (year-week), a computed category, a mathematical bucket, or a substring of a field. This lets you create flexible analytical groupings without requiring pre-computed bucket fields in your stored documents.
// Group orders by price bucket: 0-99, 100-499, 500+
db.orders.aggregate([{
$group: {
_id: {
$switch: {
branches: [
{ case: { $lt: ['$amount', 100] }, then: 'small' },
{ case: { $lt: ['$amount', 500] }, then: 'medium' }
],
default: 'large'
}
},
count: { $sum: 1 },
totalRevenue: { $sum: '$amount' }
}
}]);Two-Stage Grouping
Complex analytics often require two $group stages in sequence: the first groups at a detailed level (e.g., by user), and the second groups the first stage's results at a higher level (e.g., by region). This two-stage pattern avoids nested $group expressions and produces cleaner, more understandable pipelines.
// Average orders per user, per region
db.orders.aggregate([
// Stage 1: sum per user
{ $group: {
_id: { userId: '$userId', region: '$region' },
userOrderCount: { $sum: 1 }
}},
// Stage 2: average of those sums, per region
{ $group: {
_id: '$_id.region',
avgOrdersPerUser: { $avg: '$userOrderCount' },
uniqueUsers: { $sum: 1 }
}}
]);$group Performance: No Index Available
Unlike $match, the $group stage cannot use an index—it must process all documents passed to it. This is why reducing the input with an early $match is critical. For very large datasets where $group uses too much memory, set allowDiskUse: true to spill to disk. Alternatively, pre-computing and storing aggregated values (the Computed Pattern) avoids runtime grouping on hot paths.
// Allow disk use for large aggregations
db.orders.aggregate(
[
{ $match: { year: 2024 } },
{ $group: { _id: '$productId', revenue: { $sum: '$amount' } } },
{ $sort: { revenue: -1 } }
],
{ allowDiskUse: true } // spill to disk if memory limit exceeded
);Quick Check
Test your understanding of the $group stage in the aggregation pipeline.
Lesson Recap
In this lesson you learned: $group collapses documents by a key defined in the _id field, accumulators like $sum, $avg, $min, $max, $push compute aggregate values per group, and two-stage grouping enables hierarchical analytics. Next up we explore $sort, $limit, and $skip to order and paginate aggregation results.
เรียนรู้ JavaScript ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “$group: การรวมข้อมูลและการคำนวณยอดรวม” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “$group: การรวมข้อมูลและการคำนวณยอดรวม” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส MongoDB Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “$group: การรวมข้อมูลและการคำนวณยอดรวม”
ผู้เรียนจะจัดกลุ่มเอกสารตามคีย์ และคำนวณผลรวม ค่าเฉลี่ย จำนวน และค่ารวมประเภทอื่น ๆ ด้วย $group คุณปฏิบัติ MongoDB Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน MongoDB Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน MongoDB Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “$group: การรวมข้อมูลและการคำนวณยอดรวม” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน MongoDB Academy นี้ได้ไหม
ได้ บทเรียน MongoDB Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- แนวคิดไปป์ไลน์: ขั้นตอน ตัวดำเนินการ และนิพจน์
- $match และ $project: การกรองและการปรับรูปแบบ
- $group: การรวมข้อมูลและการคำนวณยอดรวม
- $sort, $limit และ $skip ในไปป์ไลน์