Du kan faktiskt göra något sånt här med "projekt" först, men för mig är det lite kontraintuitivt att kräva ett $project
skede innan hand:
Aggregation agg = newAggregation(
project("quantity")
.andExpression("dayOfMonth(date)").as("day")
.andExpression("month(date)").as("month")
.andExpression("year(date)").as("year")
.andExpression("price * quantity").as("totalAmount"),
group(fields().and("day").and("month").and("year"))
.avg("quantity").as("averavgeQuantity")
.sum("totalAmount").as("totalAmount")
.count().as("count")
);
Som jag sa, kontraintuitivt eftersom du bara borde kunna deklarera allt detta under $group
skede, men medhjälparna verkar inte fungera på det här sättet. Serialiseringen blir lite rolig (omsluter datumoperatörsargumenten med arrayer) men det verkar fungera. Men ändå är detta två pipeline-steg snarare än ett.
Vad är problemet med detta? Tja, genom att separera stadierna stadierna tvingar "projektdelen" fram bearbetningen av alla dokument i pipelinen för att få fram de beräknade fälten, det betyder att den går igenom allt innan den går vidare till gruppstadiet.
Skillnaden i handläggningstid kan tydligt ses genom att köra frågorna i båda formerna. Med ett separat projektsteg tar det tre gånger längre tid på min hårdvara att köra än frågan där alla fält beräknas under "grupp"-operationen.
Så det verkar som det enda nuvarande sättet att konstruera detta på rätt sätt är att bygga pipeline-objektet själv:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(SpringMongoConfig.class);
MongoOperations mongoOperation = (MongoOperations) ctx.getBean("mongoTemplate");
BasicDBList pipeline = new BasicDBList();
String[] multiplier = { "$price", "$quantity" };
pipeline.add(
new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject("month", new BasicDBObject("$month", "$date"))
.append("day", new BasicDBObject("$dayOfMonth", "$date"))
.append("year", new BasicDBObject("$year", "$date"))
)
.append("totalPrice", new BasicDBObject(
"$sum", new BasicDBObject(
"$multiply", multiplier
)
))
.append("averageQuantity", new BasicDBObject("$avg", "$quantity"))
.append("count",new BasicDBObject("$sum",1))
)
);
BasicDBObject aggregation = new BasicDBObject("aggregate","collection")
.append("pipeline",pipeline);
System.out.println(aggregation);
CommandResult commandResult = mongoOperation.executeCommand(aggregation);
Eller om allt det här verkar vara förvirrat för dig, så kan du alltid arbeta med JSON-källan och analysera det. Men självklart måste den vara giltig JSON:
String json = "[" +
"{ \"$group\": { "+
"\"_id\": { " +
"\"month\": { \"$month\": \"$date\" }, " +
"\"day\": { \"$dayOfMonth\":\"$date\" }, " +
"\"year\": { \"$year\": \"$date\" } " +
"}, " +
"\"totalPrice\": { \"$sum\": { \"$multiply\": [ \"$price\", \"$quantity\" ] } }, " +
"\"averageQuantity\": { \"$avg\": \"$quantity\" }, " +
"\"count\": { \"$sum\": 1 } " +
"}}" +
"]";
BasicDBList pipeline = (BasicDBList)com.mongodb.util.JSON.parse(json);