乐闻世界logo
搜索文章和话题

How to use Mongoose aggregation framework and what are the common operations?

2月22日 20:07

Mongoose Aggregation Framework is MongoDB's powerful data processing tool that allows complex data transformation and calculation operations on documents. Mongoose provides an interface fully compatible with MongoDB aggregation pipelines.

Basic Aggregation Operations

Using aggregate() Method

javascript
const results = await User.aggregate([ { $match: { age: { $gte: 18 } } }, { $group: { _id: '$city', count: { $sum: 1 } } } ]);

Aggregation Pipeline Stages

1. $match - Filter Documents

javascript
// Filter users aged 18 or older const results = await User.aggregate([ { $match: { age: { $gte: 18 } } } ]); // Multi-condition filtering const results = await User.aggregate([ { $match: { age: { $gte: 18 }, status: 'active' }} ]);

2. $group - Group Statistics

javascript
// Group by city and count users const results = await User.aggregate([ { $group: { _id: '$city', count: { $sum: 1 }, avgAge: { $avg: '$age' } }} ]); // Multi-field grouping const results = await Order.aggregate([ { $group: { _id: { city: '$city', status: '$status' }, totalAmount: { $sum: '$amount' }, count: { $sum: 1 } }} ]);

3. $project - Project Fields

javascript
// Select specific fields const results = await User.aggregate([ { $project: { name: 1, email: 1, fullName: { $concat: ['$firstName', ' ', '$lastName'] } }} ]); // Exclude fields const results = await User.aggregate([ { $project: { password: 0, __v: 0 }} ]);

4. $sort - Sorting

javascript
// Sort by age ascending const results = await User.aggregate([ { $sort: { age: 1 } } ]); // Multi-field sorting const results = await User.aggregate([ { $sort: { city: 1, age: -1 } } ]);

5. $limit and $skip - Pagination

javascript
// Paginated query const page = 2; const pageSize = 10; const results = await User.aggregate([ { $skip: (page - 1) * pageSize }, { $limit: pageSize } ]);

6. $lookup - Join Queries

javascript
// Join order data const results = await User.aggregate([ { $match: { _id: userId } }, { $lookup: { from: 'orders', localField: '_id', foreignField: 'userId', as: 'orders' }} ]); // Multiple joins const results = await User.aggregate([ { $lookup: { from: 'orders', localField: '_id', foreignField: 'userId', as: 'orders' }}, { $lookup: { from: 'reviews', localField: '_id', foreignField: 'userId', as: 'reviews' }} ]);

7. $unwind - Unwind Arrays

javascript
// Unwind tags array const results = await User.aggregate([ { $unwind: '$tags' }, { $group: { _id: '$tags', count: { $sum: 1 } }} ]); // Preserve empty arrays const results = await User.aggregate([ { $unwind: { path: '$tags', preserveNullAndEmptyArrays: true } } ]);

Advanced Aggregation Operations

Array Operations

javascript
// $push - Add to array const results = await User.aggregate([ { $group: { _id: '$city', users: { $push: '$name' } }} ]); // $addToSet - Add to set (deduplicate) const results = await User.aggregate([ { $group: { _id: '$city', uniqueTags: { $addToSet: '$tags' } }} ]); // $first and $last - Get first and last const results = await User.aggregate([ { $sort: { createdAt: 1 } }, { $group: { _id: '$city', firstUser: { $first: '$name' }, lastUser: { $last: '$name' } }} ]);

Conditional Operations

javascript
// $cond - Conditional expression const results = await User.aggregate([ { $project: { name: 1, ageGroup: { $cond: { if: { $gte: ['$age', 18] }, then: 'adult', else: 'minor' } } }} ]); // $ifNull - Null handling const results = await User.aggregate([ { $project: { name: 1, displayName: { $ifNull: ['$displayName', '$name'] } }} ]);

Date Operations

javascript
// Group by date const results = await Order.aggregate([ { $group: { _id: { year: { $year: '$createdAt' }, month: { $month: '$createdAt' }, day: { $dayOfMonth: '$createdAt' } }, total: { $sum: '$amount' }, count: { $sum: 1 } }} ]); // Date range query const results = await User.aggregate([ { $match: { createdAt: { $gte: new Date('2024-01-01'), $lt: new Date('2025-01-01') } }} ]);

Performance Optimization

Use Indexes

javascript
// Use indexes in $match stage const results = await User.aggregate([ { $match: { email: 'john@example.com' } }, // Use index { $group: { _id: '$city', count: { $sum: 1 } } } ]);

Optimize Pipeline Order

javascript
// Before optimization const results = await User.aggregate([ { $project: { name: 1, age: 1, city: 1 } }, { $match: { age: { $gte: 18 } } } ]); // After optimization - filter first then project const results = await User.aggregate([ { $match: { age: { $gte: 18 } } }, { $project: { name: 1, age: 1, city: 1 } } ]);

Use $facet for Parallel Processing

javascript
// Execute multiple aggregation pipelines in parallel const results = await User.aggregate([ { $facet: { total: [{ $count: 'count' }], adults: [ { $match: { age: { $gte: 18 } } }, { $count: 'count' } ], byCity: [ { $group: { _id: '$city', count: { $sum: 1 } } } ] }} ]);

Practical Use Cases

Sales Statistics

javascript
const salesStats = await Order.aggregate([ { $match: { createdAt: { $gte: new Date('2024-01-01'), $lt: new Date('2025-01-01') } }}, { $group: { _id: { year: { $year: '$createdAt' }, month: { $month: '$createdAt' } }, totalRevenue: { $sum: '$amount' }, orderCount: { $sum: 1 }, avgOrderValue: { $avg: '$amount' } }}, { $sort: { '_id.year': 1, '_id.month': 1 } } ]);

User Activity Analysis

javascript
const userActivity = await User.aggregate([ { $lookup: { from: 'activities', localField: '_id', foreignField: 'userId', as: 'activities' }}, { $project: { name: 1, email: 1, activityCount: { $size: '$activities' }, lastActivity: { $max: '$activities.createdAt' } }}, { $sort: { activityCount: -1 } } ]);

Best Practices

  1. Use $match early: Reduce the amount of data processed
  2. Use indexes appropriately: Utilize indexes in $match stage
  3. Limit result count: Use $limit to avoid processing too much data
  4. Avoid deep nesting: Keep pipelines concise
  5. Use $facet: Process multiple aggregations in parallel
  6. Monitor performance: Use explain() to analyze aggregation performance
  7. Batch process large data: Use batch processing for large datasets
标签:Mongoose