เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล
ผู้เรียนจะปรับโครงสร้างไปป์ไลน์การรวมข้อมูลเพื่อย้าย $match และ $project ไปไว้ช่วงต้น หลีกเลี่ยง $unwind ก่อน $match และใช้ allowDiskUse สำหรับการเรียงลำดับขนาดใหญ่
เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล เป็นบทเรียน MongoDB Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน MongoDB Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
บางส่วนของบทเรียนนี้ยังไม่ได้รับการแปล และแสดงเป็นภาษาอังกฤษ
Aggregation Performance: The Big Picture
Aggregation pipelines can be expensive — they can scan millions of documents, build large in-memory structures, and block for seconds. The key to fast pipelines is applying data-reduction stages as early as possible so later stages work on the smallest possible dataset. MongoDB also has an internal optimizer that automatically reorders certain stages, but understanding manual optimizations gives you the most control.
Put $match Early: Filter Before You Transform
$match is MongoDB's filter stage. Placing it as early as possible in the pipeline reduces the number of documents that flow into every subsequent stage. If $match can use an index, it becomes an extremely fast first step. Even a $match without an index early in the pipeline is better than a late one — it avoids processing documents that will be discarded anyway.
// BAD: $group processes all 1M docs, then $match discards most
db.orders.aggregate([
{ $group: { _id: '$status', total: { $sum: '$amount' } } },
{ $match: { _id: 'pending' } } // late match
])
// GOOD: $match first — only 'pending' docs enter $group
db.orders.aggregate([
{ $match: { status: 'pending' } }, // early match, uses index
{ $group: { _id: '$customerId', total: { $sum: '$amount' } } }
])Put $project Early: Reduce Document Size
Use $project early to drop fields you will not need in later stages. Fewer fields per document means smaller in-memory representations flowing through the pipeline, reducing memory pressure and CPU time. Only project away fields you are certain are not needed — an over-aggressive early $project that drops a field used in a later stage will fail.
// Drop large, unused fields early
db.products.aggregate([
{ $match: { category: 'electronics' } },
// Remove bulky description and image fields early
{ $project: { name: 1, price: 1, stock: 1 } },
{ $group: { _id: null, avgPrice: { $avg: '$price' } } }
])Pipeline Optimizer: Auto-Rewrites
MongoDB's aggregation optimizer automatically applies several rewrites before executing your pipeline. Key auto-rewrites: 1) Merges consecutive $match stages into one. 2) Moves $match before $skip and $limit when possible. 3) Merges consecutive $limit stages. 4) Pushes $match before $lookup to filter before the join. Use explain() to see the optimized pipeline.
// View the optimizer's rewritten pipeline
db.orders.explain().aggregate([
{ $lookup: { from: 'customers', localField: 'customerId',
foreignField: '_id', as: 'customer' } },
{ $match: { 'customer.country': 'US' } }
])
// Optimizer may push $match before $lookup if fields allowAvoid $unwind Before $match
$unwind explodes an array into multiple documents — one per array element. If you place $match after $unwind, you pay the full cost of expansion before filtering. When possible, filter before the $unwind to reduce the number of array elements that need expansion. This can reduce document count by an order of magnitude on large arrays.
// BAD: unwind first creates N*arraySize docs, then filter
db.blogs.aggregate([
{ $unwind: '$tags' },
{ $match: { tags: 'mongodb' } }
])
// GOOD: filter the root document first, then unwind
db.blogs.aggregate([
{ $match: { tags: 'mongodb' } }, // uses index on tags array
{ $unwind: '$tags' },
{ $match: { tags: 'mongodb' } } // refine after unwind
])Index Coverage for $match and $sort
The first $match stage of a pipeline can use a collection index just like a find() query. The first $sort stage can also use an index to avoid an in-memory sort — but only if it appears before any stage that modifies the document shape (like $project or $group). Structure your pipelines so early $match and $sort stages benefit from indexes.
// Index supports $match and $sort at the start
db.events.createIndex({ userId: 1, createdAt: -1 })
db.events.aggregate([
{ $match: { userId: 'u123' } }, // uses index
{ $sort: { createdAt: -1 } }, // uses index sort order
{ $limit: 20 },
{ $project: { _id: 0, type: 1, payload: 1 } }
])allowDiskUse for Large Sorts
By default, each aggregation stage is limited to 100 MB of RAM. If a $sort, $group, or $bucket stage exceeds this limit, the pipeline fails with an error. Setting allowDiskUse: true lets the pipeline spill to disk, enabling arbitrarily large sorts at the cost of slower I/O. The right fix is usually to add an index or filter more aggressively before the sort.
// Allow spill to disk for large aggregations
db.events.aggregate(
[
{ $match: { year: 2024 } },
{ $sort: { amount: -1 } },
{ $group: { _id: '$region', total: { $sum: '$amount' } } }
],
{ allowDiskUse: true }
)$lookup Performance: Filter Before Joining
$lookup is the aggregation equivalent of a SQL JOIN and is one of the most expensive stages. To minimise cost: 1) Place $match before $lookup so fewer documents need joining. 2) Ensure the joined collection has an index on the foreignField. 3) Use the pipeline form of $lookup with a $match inside it to filter the joined results immediately.
// Ensure foreignField is indexed
db.customers.createIndex({ _id: 1 }) // usually already indexed
// Use pipeline $lookup with internal $match to reduce joined docs
db.orders.aggregate([
{ $match: { status: 'pending' } },
{ $lookup: {
from: 'customers',
let: { cid: '$customerId' },
pipeline: [
{ $match: { $expr: { $eq: ['$_id', '$$cid'] } } },
{ $project: { name: 1, email: 1 } } // trim early
],
as: 'customer'
}}
])Use $limit Early in Pagination Pipelines
When building paginated list endpoints, push $limit as early as possible after the filter and sort. A pipeline that processes 100,000 documents through $lookup and $addFields before limiting to 20 is 5,000x more expensive than one that limits first. Keyset pagination with a range filter often eliminates the need for $skip entirely.
// Efficient pagination: limit BEFORE expensive stages
db.products.aggregate([
{ $match: { category: 'books' } },
{ $sort: { rating: -1 } },
{ $limit: 20 }, // limit early!
{ $lookup: { from: 'reviews',
localField: '_id', foreignField: 'productId', as: 'reviews' } }
])Pre-Compute With Materialised Views
For expensive aggregations that power dashboards or reports, consider materialised views using $merge or $out. Run the heavy aggregation on a schedule (e.g., every hour) and write results to a dedicated collection. Queries against the materialised view are cheap point-lookups instead of expensive pipeline scans. Atlas also supports On-Demand Materialised Views via triggers.
// Materialise daily revenue summary
db.orders.aggregate([
{ $match: { createdAt: { $gte: ISODate('2025-01-01') } } },
{ $group: { _id: '$region', revenue: { $sum: '$amount' } } },
{ $merge: {
into: 'revenue_summary',
whenMatched: 'replace',
whenNotMatched: 'insert'
}}
])Profiling Aggregation Pipelines
Use .explain('executionStats') on an aggregate to see how many documents each stage emitted. Look for stages where nReturned drops sharply — that is where the real work happens. If a stage is still processing millions of documents, add a $match or improve the index before it. For Atlas, the Query Profiler also shows aggregation pipeline performance over time.
db.orders.explain('executionStats').aggregate([
{ $match: { status: 'shipped' } },
{ $group: { _id: '$region', total: { $sum: '$amount' } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
])
// Check: nReturned per stage, executionTimeMillisEstimateQuick Check
Test your understanding of MongoDB & NoSQL Databases concepts from this lesson.
Lesson Recap
In this lesson you learned: push $match and $project as early as possible to minimize document volume in later stages, ensure the first $match and $sort use indexes to avoid collection scans and in-memory sorts, and use allowDiskUse for unavoidably large sorts, but prefer better indexes or earlier filters as the permanent fix. Next up we explore Atlas Data Federation.
เรียนรู้ JavaScript ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 30
- บทเรียน
- 120
คำถามที่พบบ่อย
บทเรียน “เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส MongoDB Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส MongoDB Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล”
ผู้เรียนจะปรับโครงสร้างไปป์ไลน์การรวมข้อมูลเพื่อย้าย $match และ $project ไปไว้ช่วงต้น หลีกเลี่ยง $unwind ก่อน $match และใช้ allowDiskUse สำหรับการเรียงลำดับขนาดใหญ่ คุณปฏิบัติ MongoDB Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน MongoDB Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน MongoDB Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน MongoDB Academy นี้ได้ไหม
ได้ บทเรียน MongoDB Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ตัวสร้างโปรไฟล์ฐานข้อมูลและบันทึกการค้นหาที่ช้า
- กฎคำนำหน้าดัชนีผสมและหลักการ ESR
- การตัดกันของดัชนีเทียบกับดัชนีผสม
- เคล็ดลับการปรับประสิทธิภาพไปป์ไลน์การรวมข้อมูล