Spring Data MongoDB聚合查询时类型转换失败问题排查
问题分析与解决方案
你的问题核心是数据库中cost字段的字符串值存在无法转换为数字的情况,加上ToDouble.toDouble()方法没有处理转换失败的逻辑,导致MongoDB抛出转换错误。
错误原因
从报错信息看,MongoDB在尝试将cost字段的字符串转数字时,遇到了无法完全解析为数字的内容(比如包含非数字字符、格式错误的字符串,或者空值),而默认的转换逻辑没有容错机制,直接抛出异常。
解决步骤
1. 先排查数据库数据
先检查item集合中refrenceId为630722f47b409045ff2b98ee的文档,确认cost字段的字符串内容:
- 是否有非数字字符(比如"123.45元"、"abc")
- 是否有空字符串或null值
- 是否使用了非标准的小数点分隔符(比如用逗号代替点,如"123,45")
2. 修改聚合查询,添加转换容错
替换原来的ToDouble.toDouble(),改用MongoDB的$convert操作符,显式指定转换失败和空值的默认值,避免报错。修改后的Java代码如下:
Aggregation agg = Aggregation.newAggregation( match(Criteria.where("refrenceId").is("630722f47b409045ff2b98ee")), group().sum(new AggregationExpression() { @Override public Document toDocument(AggregationOperationContext context) { return new Document("$convert", new Document("input", "$cost") .append("to", "double") .append("onError", 0.0) // 转换失败时返回0 .append("onNull", 0.0) // 字段为null时返回0 ); } }).as("totalCost") ); // 用Map接收结果,避免Item类的类型映射问题 Map<String, Double> resultMap = mongoConfig.getMongoTemplate() .aggregate(agg, "item", Map.class) .getMappedResults().get(0); Double totalCost = resultMap.get("totalCost");
3. 高精度需求的优化(可选)
如果你的业务对精度要求高,不建议转double(会丢失精度),可以用MongoDB的$toDecimal操作符(MongoDB 4.0+支持),转换为高精度小数后再求和,代码调整如下:
Aggregation agg = Aggregation.newAggregation( match(Criteria.where("refrenceId").is("630722f47b409045ff2b98ee")), group().sum(new AggregationExpression() { @Override public Document toDocument(AggregationOperationContext context) { return new Document("$toDecimal", new Document("$convert", new Document("input", "$cost") .append("to", "string") .append("onError", "0") .append("onNull", "0") ) ); } }).as("totalCost") ); // 用BigDecimal接收高精度结果 Map<String, BigDecimal> resultMap = mongoConfig.getMongoTemplate() .aggregate(agg, "item", Map.class) .getMappedResults().get(0); BigDecimal totalCost = resultMap.get("totalCost");
额外建议
长期来看,最好把数据库中cost字段的类型改成数值类型(比如Decimal128),从根源避免字符串转换的问题,同时保证精度。
内容的提问来源于stack exchange,提问作者Arushi
相关产品推荐
相关产品推荐

