MongoDB中基于对象键的日期范围过滤与子文档返回需求
Solution: Filter and Project MongoDB Documents by Date Range in Dynamic Keys
To retrieve documents where the analytics.days keys fall within a specified date range (and retain only those matching days in the result), you’ll use MongoDB’s aggregation framework. Here’s a practical, step-by-step solution:
Step 1: Define Your Date Range
First, convert your start/end date strings into proper Date objects to enable accurate range comparisons. For example:
const startDate = new Date("2019-01-15"); const endDate = new Date("2019-01-25"); endDate.setHours(23, 59, 59, 999); // Ensure we include the full end day
Step 2: Aggregation Pipeline
Use this pipeline to filter qualifying documents and keep only the days within your range:
db.yourCollectionName.aggregate([ // Convert the days object into an array of key-value pairs for processing { $addFields: { "analytics.daysArray": { $objectToArray: "$analytics.days" } } }, // Parse each date string (DD-MM-YYYY) into a Date object { $addFields: { "analytics.daysArray": { $map: { input: "$analytics.daysArray", as: "day", in: { k: "$$day.k", v: "$$day.v", parsedDate: { $dateFromString: { dateString: "$$day.k", format: "%d-%m-%Y" // Critical for matching your date format } } } } } } }, // Keep only documents with at least one day in the target range { $match: { "analytics.daysArray.parsedDate": { $gte: startDate, $lte: endDate } } }, // Filter the days array to retain only matches, then convert back to an object { $addFields: { "analytics.days": { $arrayToObject: { $filter: { input: "$analytics.daysArray", cond: { $and: [ { $gte: ["$$this.parsedDate", startDate] }, { $lte: ["$$this.parsedDate", endDate] } ] } } } } } }, // Clean up the temporary array field we added { $project: { "analytics.daysArray": 0 } } ])
How It Works
Let’s break down each stage to understand the logic:
- $objectToArray: Converts the dynamic
analytics.daysobject into an array of{k: dateString, v: dayData}pairs, making it easy to process individual dates. - $map + $dateFromString: Parses each date string into a proper
Dateobject—this is essential because we can’t compare string dates reliably (e.g., "28-12-2018" vs "20-01-2019" would be out of order as strings). - $match: Filters out any documents that don’t have at least one day within your specified range.
- $filter + $arrayToObject: Keeps only the days that fall within the range, then converts the filtered array back into an object to replace the original
analytics.days. - $project: Removes the temporary
daysArrayfield to clean up the final result.
Example Output
For your sample input and date range (15-01-2019 to 25-01-2019), the result will be exactly what you requested:
{ "_id": ObjectId("5c51b3e2bb564f3f1ccf84c2"), "createdAt": 1548858338324, "updatedAt": 1548858843028, "teamId": "ef08f13", "analytics": { "aggregate": { "averageViewTime": 5.6000000000000005, "averageClicks": 2.5, "totalViews": 2, "totalVisits": 4 }, "days": { "20-01-2019": { "dayAvgViewTime": 5.6000000000000005, "dayAvgClicks": 2.5, "dayViews": 2, "dayVisits": 4 } } } }
内容的提问来源于stack exchange,提问作者Aman kumar
相关产品推荐
相关产品推荐

