在 Spring Boot 版本升级之前,聚合工作正常。升级到 2.5.14 后,我遇到 MongoTemplate.aggregate(Aggregationgregation, Class inputType, Class outputType) 的问题:
org.springframework.data.mapping.MappingException: Cannot convert [] of type class java.util.ArrayList into an instance of class java.lang.String! Implement a custom Converter<class java.util.ArrayList, class java.lang.String> and register it with the CustomConversions.
我最近在从 Spring Boot 2.4 升级到 Spring Boot 2.5 时遇到了这个问题(我相信是 Spring Data MongoDB 3.1.5 到 3.2)
我正在
无法将 java.util.ArrayList 类型的 [0] 转换为 java.math.BigDecimal 类的实例
我继续升级,Spring Boot 2.6,然后是 Spring Boot 2.7,确信新版本会修复该错误。
当这不起作用时,我花了几个小时进行搜索,但无法在任何地方找到导致先前工作查询中断的原因的解释。在我的研究中,我发现对 MappingMongoConverter 进行了许多更改,其中之一暴露了我的查询中的明显缺陷。
假设您正在尝试填充 ArrayList
public class MyClass {
private long a;
private BigDecimal b;
private BigDecimal c;
}
你有一个像这样的聚合组:
Aggregation.group("a").sum("b").as("b").addToSet("c").as("c");
在这个聚合组中,我试图获取按“a”分组的“b”的总和,其中“c”在每个“a”组中的所有行上都是相同的,所以我只需要添加它即可。
如果手动运行查询,使用 $addToSet 时您将看到从 MongoDB 返回的原始 JSON,如下所示:
{
"a" : NumberLong(0),
"b" : NumberDecimal("1"),
"c" : [ NumberDecimal("2") ]
}
显然 $push 和 $addToSet (也许还有其他)创建一个数组并将请求的值添加到数组中。
旧的 MappingMongoConverter 通过从“c”数组中获取第一个值来填充 MyClass。新的 MappingMongoConverter 并不那么宽容,它会给你一个错误,告诉你你正在尝试将 ArrayList 转换为单个值
我的解决方法是将我的聚合组更改为在“c”上使用 $first 而不是:
Aggregation.group("a").sum("b").as("b").first("c").as("c");
现在我从查询返回的原始 JSON 看起来像这样:
{
"a" : NumberLong(0),
"b" : NumberDecimal("1"),
"c" : NumberDecimal("2")
}
我不再收到“无法转换 ArrayList”错误。