使用spring-boot-starter-data-mongodb查询MongoDB嵌套文档遇问题
问题解答
一、hasBudget Criteria 的问题原因及修复
你的hasBudget Criteria写法错误:直接使用gte("$costs.costPerClick")会把"$costs.costPerClick"当作字符串常量而非文档内的字段引用,MongoDB实际执行的是balance >= "$costs.costPerClick"的数值与字符串比较,永远不成立,因此查询结果为0。
要实现同文档内字段的比较,必须使用MongoDB的$expr操作符来引用字段。修复后的hasBudget方法如下:
public static Criteria hasBudget() { return Criteria.where("$expr").is(new Document("$or", Arrays.asList( new Document("$gte", Arrays.asList("$balance", "$costs.costPerClick")), new Document("$gte", Arrays.asList("$balance", "$costs.costPerImpression")) ))); }
或者使用Spring Data MongoDB更简洁的表达式写法:
public static Criteria hasBudget() { return new Criteria().orOperator( Criteria.where("$expr").expression("balance >= costs.costPerClick"), Criteria.where("$expr").expression("balance >= costs.costPerImpression") ); }
修改后MongoDB会正确将balance与文档内的costs.costPerClick、costs.costPerImpression字段做数值比较,符合业务逻辑。
二、聚合查询返回对象全null的修复
你的聚合查询使用Aggregation.project()时,仅定义了hasBudget字段,未保留原文档的其他字段,导致映射到BannerDoc时所有属性均为null。
解决方法是用Aggregation.addFields()替代project(),addFields()会保留原文档所有字段,仅新增hasBudget字段:
Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(Criteria.where("enabled").is(true)), // 用addFields保留原有字段,新增hasBudget判断 Aggregation.addFields() .addFieldWithValue("hasBudget", AggregationExpression.from("balance >= costs.costPerClick && balance >= costs.costPerImpression")) .build(), Aggregation.match(Criteria.where("hasBudget").is(true)) ); List<BannerDoc> banners = mongoTemplate.aggregate(aggregation, "banners", BannerDoc.class).getMappedResults();
若坚持使用project(),需显式列出所有需要保留的字段:
Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(Criteria.where("enabled").is(true)), Aggregation.project("_id", "balance", "costs", "createdAt", "description", "enabled", "imageUrl", "link", "metrics", "priority", "title", "updatedAt", "validFrom", "validTo") .andExpression("balance >= costs.costPerClick && balance >= costs.costPerImpression") .as("hasBudget"), Aggregation.match(Criteria.where("hasBudget").is(true)) );
显然addFields()更简洁且不易出错,推荐使用。
内容的提问来源于stack exchange,提问作者user3187960
相关产品推荐
相关产品推荐

