You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 17:33:23