如何使用 MongoDB Java driver 按聚合计算的平均值排序?
在聚合管道的 Aggregates.group(...) 后添加 Aggregates.sort(...),即可按 Average Vendor Transaction Sent 排序。无需先保存到新集合,也不必在 Java 中另行排序。
为什么计算结果也能按字段名排序?
Accumulators.avg("Average Vendor Transaction Sent", "$amount sent") 会把平均值写入分组结果的 Average Vendor Transaction Sent 字段。
原始文档虽然没有这个字段,但 $group 执行后的文档已包含它,例如:
{
"_id": "HECTOR'S YOUR I",
"Average Vendor Transaction Sent": 27.72
}
后续管道阶段可以使用前面阶段生成的字段,因此可以通过 Sorts 引用它。
在 $group 后添加排序阶段
下面按平均交易金额从大到小排序:
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Accumulators;
import com.mongodb.client.model.Aggregates;
import com.mongodb.client.model.Sorts;
import org.bson.Document;
import java.util.Arrays;
private static AggregateIterable<Document> averageVendorTotalSent(
MongoCollection<Document> collection) {
return collection.aggregate(Arrays.asList(
Aggregates.group(
"$transaction vendor",
Accumulators.avg(
"Average Vendor Transaction Sent",
"$amount sent"
)
),
Aggregates.sort(
Sorts.descending("Average Vendor Transaction Sent")
)
));
}
如果需要从小到大排序,将排序阶段改成:
Aggregates.sort(
Sorts.ascending("Average Vendor Transaction Sent")
)
其中,Sorts.descending(...) 或 Sorts.ascending(...) 构造排序条件,Aggregates.sort(...) 将条件包装成聚合管道中的 $sort 阶段。
字段名和管道顺序要注意什么?
排序时传入字段名,不要添加 $ 前缀:
Sorts.descending("Average Vendor Transaction Sent")
原代码中的 "$amount sent" 是聚合表达式中的字段引用;Sorts.descending(...) 的参数则是排序字段名,两处写法不同。字段名中的空格可以保留,但名称需要与 Accumulators.avg(...) 定义的输出字段完全一致。
排序阶段必须放在 $group 后面,因为平均值到这时才生成。如果在 $group 前按 amount sent 排序,排列的是原始交易记录,无法让最终结果按各商家的平均金额排列;$group 本身也不保证输出顺序。
这个需求不需要额外的 $project 阶段。如果平均值相同,还希望按商家名称排列,可以增加 _id 作为第二排序条件:
Aggregates.sort(Sorts.orderBy(
Sorts.descending("Average Vendor Transaction Sent"),
Sorts.ascending("_id")
))
这里的 _id 是 $group 输出的分组键,对应原始文档中的 transaction vendor。
备注:内容仅供参考。
