【问题标题】:MongoTemplate aggregation not mapping the resultMongoTemplate 聚合未映射结果
【发布时间】:2019-06-28 01:38:20
【问题描述】:

我正在尝试使用 MongoTemplate 和聚合框架在 Spring Boot 项目中运行聚合管道。

我的查询毫无例外地执行。但是当我尝试在AggregationResults 实例上调用getMappedResults() 时,它总是给我一个空列表。但是,如果我在调试器中检查结果,我可以看到 getRawResults() 方法返回值。

我正在使用 spring-boot 版本 1.5.9.RELEASEspring-boot-starter-data-mongodb 版本 2.1.2.发布

我不确定我做错了什么。


以下是聚合的代码

    GroupOperation groupOperation = Aggregation.group("field1", "field2")
            .count().as("count")
            .max("timestamp").as("timestamp");

    ProjectionOperation projectionOperation = Aggregation.project("field1", "field2", "count", "timestamp");

    DBObject cursor = new BasicDBObject(10);
    AggregationOptions aggregationOptions = Aggregation.newAggregationOptions().cursor(cursor).build();

    Aggregation aggregation = Aggregation.newAggregation(groupOperation, projectionOperation).withOptions(aggregationOptions);
    AggregationResults<Res> activities = mongoTemplate.aggregate(aggregation, "test_collection", Res.class);

以下是我尝试在其中映射结果的类

public class Res {
    public String field1;

    public String field2;

    public Long timestamp;

    public Integer count;

    public Res() {
    }

    public Res(String field1, String field2, Long timestamp, Integer count) {
        this.field1 = field1;
        this.field2 = field2;
        this.timestamp = timestamp;
        this.count = count;
    }
}

注意 如果我跳过 AggregationOptions 中的光标,我会收到以下错误

'The 'cursor' option is required, except for aggregate with the explain argument'

【问题讨论】:

    标签: mongodb spring-boot spring-data spring-mongodb


    【解决方案1】:

    根据我的经验,GroupOperation 将产生具有以下方案的文档数组:

    {
      _id: {
        field1:"field1",
        field2:"field2"
      },
      count: countResult,
      timestamp:timestamp
    }
    

    在这种情况下,ProjectOperation 不会生成映射您的实体类的文档。

    我建议您通过在您的 application.properties 文件中添加 logging.level.org.springframework.data=debug 来激活调试日志记录。通过这种方式,您可以查看发送到 MongoDB 的请求并在 MongoShell 中重现它们,以便查看每个聚合操作的结果。

    测试由于GroupOperation 结果而导致实体类未正确映射的假设的快速方法是添加Setters 并删除第二个Constructorcounttimestamp 属性应正确映射,Res 对象将仅使用 counttimestamp 属性创建。

    注意From this post, 聚合需要游标,因为 Mongo 3.6 和 MongoDB 3.6 需要 spring 1.5.10.RELEASE 进行聚合操作。考虑将 Spring-boot 升级到 1.5.10 以跳过光标。

    【讨论】:

    • 我尝试了您的建议并添加了设置器并删除了所有构造函数,但默认构造函数除外。但是,它仍然没有映射结果。但是当我升级到 spring 1.5.10 时它开始工作了。我不确定这是否是 Spring 版本特有的问题。
    • 您是否按照我的建议修改了您的ProjectOperation?也不确定这与 Spring 版本有关。尽管如此,构建 Spring AggregationOperation 的最佳方法是从调试日志中复制 MongoDB 查询并在 MongoShell 中测试每个操作。
    • 是的,我按照你的建议修改了项目操作,但还是不行。反正升级spring版本后,好像可以了
    【解决方案2】:

    我也在努力解决聚合不映射复合 ID 的问题,结果我误解了映射的工作原理。 (我建议阅读有关映射的 Spring 文档:https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mapping-chapter

    还值得注意的是,映射行为在 Spring Boot 2.1.8 和 2.3.4 之间发生了变化(我只是在升级时遇到了这个问题)。在 2.1.8 中,无论对错,您都可以将复合键映射到单个 java 类中的不同字段(例如问题中发布的原始 Res 类)。

    charlycou 的回答在返回的文档的代码 sn-p 中提供了线索(注意 _id 是一个 json 对象)

        {
         _id: {
           field1:"field1",
           field2:"field2"
         },
         count: countResult,
         timestamp:timestamp
        }
    

    为了使映射在此复合键场景中正常工作,请创建一个 java 类来表示复合键。例如:

        public class ResId {
            public String field1;
            public String field2; 
         
            public ResId(String field1, String field2){
               this.field1 = field1;
               this.field2 = field2;
           }
        }
        
        public class Res {
            @Id
            public ResId resId;
        
            public Long timestamp;
        
            public Integer count;
        
            public Res() {
            }
        
            public Res(ResId resId, Long timestamp, Integer count) {
                this.resId = resId;
                this.timestamp = timestamp;
                this.count = count;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2017-12-10
      • 2016-04-08
      • 1970-01-01
      • 2015-01-23
      • 2019-10-04
      • 1970-01-01
      • 1970-01-01
      • 2019-10-29
      • 1970-01-01
      相关资源
      最近更新 更多