如何使用Java Morphia改写包含$map和$arrayToObject的MongoDB聚合查询
Morphia实现指定MongoDB聚合查询的方案
前置准备
- 确保你的源集合对应的实体类已经完成Morphia映射,其中
items字段为列表类型,列表元素包含key、value两个属性 - 接收聚合结果的DTO类中,
items字段定义为Map<String, Object>类型,用于匹配$arrayToObject的输出结构
实现代码(适配Morphia 2.x版本)
import dev.morphia.Datastore; import dev.morphia.aggregation.AggregationPipeline; import static dev.morphia.aggregation.Projection.projection; import static dev.morphia.query.Expression.*; // 假设你已经初始化好Datastore实例 Datastore datastore = ...; // 构造第一个$project阶段:遍历items数组,提取k/v对 var projectStage1 = projection("items", map( field("items"), of( "k", variable("this.key"), "v", variable("this.value") ) ) ); // 构造第二个$project阶段:将k/v数组转为对象 var projectStage2 = projection("items", arrayToObject(field("items")) ); // 组装聚合管道并执行 AggregationPipeline<YourSourceEntity> pipeline = datastore.aggregate(YourSourceEntity.class) .project(projectStage1) .project(projectStage2); // 遍历结果,ResultDTO是你自定义的结果接收类 pipeline.execute(ResultDTO.class).forEachRemaining(result -> { // 处理返回结果 Map<String, Object> items = result.getItems(); // ...后续业务逻辑 });
全版本兼容方案
如果觉得API构造复杂表达式容易出错,可以直接传入原生MongoDB查询语句构造阶段,写法和原生查询完全一致,适配所有Morphia版本:
import dev.morphia.Datastore; import dev.morphia.aggregation.AggregationPipeline; import org.bson.Document; Datastore datastore = ...; // 直接用原生Mongo语句构造阶段 Document stage1 = Document.parse(""" { "$project": { "items": { "$map": { "input": "$items", "in": { "k": "$$this.key", "v": "$$this.value" } } } } } """); Document stage2 = Document.parse(""" { "$project": { "items": { "$arrayToObject": "$items" } } } """); // 组装管道执行 AggregationPipeline<YourSourceEntity> pipeline = datastore.aggregate(YourSourceEntity.class) .stage(stage1) .stage(stage2); pipeline.execute(ResultDTO.class).forEachRemaining(result -> { // 处理结果 });
注意事项
- Morphia 1.x版本的包路径为
org.mongodb.morphia,核心API用法基本一致,仅需调整导入包路径即可 - 如果聚合不需要返回源实体的其他字段,可以在project阶段添加
_id: 0等配置过滤不需要的字段,减少数据传输
内容的提问来源于stack exchange,提问作者Ankit Prasad
相关产品推荐
相关产品推荐

