Anda sebenarnya dapat melakukan sesuatu seperti ini dengan "proyek" terlebih dahulu, tetapi bagi saya itu sedikit kontra-intuitif untuk memerlukan $project
panggung sebelumnya:
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")
);
Seperti yang saya katakan, kontra-intuitif karena Anda seharusnya dapat mendeklarasikan semua ini di bawah $group
panggung, tetapi para pembantu tampaknya tidak bekerja dengan cara ini. Serialisasi keluar agak lucu ( membungkus argumen operator tanggal dengan arrays ) tetapi tampaknya berhasil. Tapi tetap saja, ini adalah dua tahap pipa, bukan satu.
Apa masalahnya dengan ini? Nah dengan memisahkan tahapan tahapan, bagian "proyek" memaksa pemrosesan semua dokumen dalam pipa untuk mendapatkan bidang yang dihitung, itu berarti melewati semuanya sebelum pindah ke babak grup.
Perbedaan waktu pemrosesan dapat dilihat dengan jelas dengan menjalankan kueri di kedua formulir. Dengan tahapan proyek yang terpisah, pada perangkat keras saya membutuhkan waktu tiga kali lebih lama untuk dieksekusi daripada kueri di mana semua bidang dihitung selama operasi "grup".
Jadi sepertinya satu-satunya cara untuk membangun ini dengan benar adalah dengan membangun objek pipa sendiri:
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);
Atau jika semua itu tampak singkat bagi Anda, maka Anda selalu dapat bekerja dengan sumber JSON dan menguraikannya. Tapi tentu saja, itu harus JSON yang valid:
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);