I’m pretty new to MongoDB and I need to group the sum of the total of all invoices for each unique date in all the documents in a collection. This is a summary of the collection, where data is stored in a key-value pair:
Document 1:
{
"data": [
{
"key": "invoice-date",
"value": {
"$date": "2023-05-04T00:00:00.000Z"
}
},
{
"key": "invoice-total",
"value": 110.29
}
]
}
Document 2:
{
"data": [
{
"key": "invoice-date",
"value": {
"$date": "2023-05-04T00:00:00.000Z"
}
},
{
"key": "invoice-total",
"value": 47.18
}
]
}
Document 3:
{
"data": [
{
"key": "invoice-date",
"value": {
"$date": "2023-05-05T00:00:00.000Z"
}
},
{
"key": "invoice-total",
"value": 22.05
}
]
}
This should be grouped into a map and the result should be as follows:
"2023-05-04T00:00:00.000Z": 157.47
"2023-05-05T00:00:00.000Z": 22.05
This what I have tried thus far in Spring 3.1.4:
MatchOperation matchStage = Aggregation.match(Criteria.where("data.key").in("invoice-date", "invoice-total"));
GroupOperation groupStage = Aggregation.group("invoice-date")
.sum(ConditionalOperators.when(Criteria.where("data.key").is("invoice-total")).then("data.value")
.otherwise(0))
.as("total");
ProjectionOperation projectionStage = Aggregation.project()
.andExpression("_id").as("invoice-date")
.andInclude("total");
Aggregation aggregation = Aggregation.newAggregation(
matchStage,
groupStage,
projectionStage);
return mongoTemplate.aggregate(aggregation, "documents", Map.class);
However, the returned total is always 0 and the date is null. How can I make the aggregation work?
2
Answers
Your query is not working as you are trying to group by "invoice-date" which is a value but not a field.
It can be solved by extracting the value from the
data
array as theinvoiceDate
andinvoiceTotal
fields (second stage).For converting the set of dates with respective total, you need to
$group
all documents into one document and convert into key-value pair.Demo @ Mongo Playground
Sorry that I am not a Spring/Java MongoDB Developer, based on what I researched, the Spring code should be as:
Instead of
$getField
I would use$arrayToObject
:Mongo Playground