Spring Boot MongoTemplate聚合投影无法新增字段问题求助
解决MongoDB聚合查询新增投影字段的问题
问题分析
你遇到的核心问题是:
- 当把
awardForContentId加入group分组键后,MongoDB会将分组结果的_id生成为包含userId和awardForContentId的对象,而你的映射类注解配置错误,导致userId被映射为整个_id对象,awardForContentId字段无法正确匹配。 - 直接在
project阶段引用awardForContentId报错,是因为group阶段后,该字段仅存在于_id对象内部,不能直接顶层引用。
解决方案1:按userId+awardForContentId分组(每个内容的积分单独统计)
如果需要统计用户针对不同内容获得的礼品积分(即同一个用户对应多条不同awardForContentId的记录),可以通过project阶段提取_id内的字段到顶层,配合正确的映射类实现。
步骤1:修正映射类
移除错误的@Id和@Field("id")注解,让字段直接匹配投影后的顶层字段:
@Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) public class RecentlyRewardedUsers { private String userId; private BigDecimal totalValueAwarded; private String awardForContentId; }
步骤2:调整聚合查询
在group之后添加project阶段,将_id中的userId和awardForContentId提取为顶层字段:
Aggregation agg = Aggregation.newAggregation( // 过滤近range天的GIFT类型交易 match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range)) .and("transactionAction").is("GIFT")), // 按userId和awardForContentId分组,统计总积分 group("userId", "awardForContentId") .sum("transactionAmount").as("totalValueAwarded"), // 投影:提取_id内的字段到顶层 project() .and("_id.userId").as("userId") .and("_id.awardForContentId").as("awardForContentId") .and("totalValueAwarded").as("totalValueAwarded"), // 分页逻辑 skip((long) pageable.getPageNumber() * pageable.getPageSize()), limit(pageable.getPageSize()) ); List<RecentlyRewardedUsers> results = mongoTemplate.aggregate(agg, Transaction.class, RecentlyRewardedUsers.class).getMappedResults();
解决方案2:按userId分组(每个用户仅一条记录,带最新的awardForContentId)
如果只需要每个用户一条记录,同时带上该用户最近获得礼品对应的awardForContentId,可以在group阶段使用first()方法获取最新的内容ID,无需将其作为分组键。
步骤1:修正映射类
使用@Id注解将_id(即分组后的userId值)映射到userId字段:
@Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) public class RecentlyRewardedUsers { @Id private String userId; private BigDecimal totalValueAwarded; private String awardForContentId; }
步骤2:调整聚合查询
先按createdDate降序排序,确保最新的交易排在前面,再通过first()方法获取最新的awardForContentId:
Aggregation agg = Aggregation.newAggregation( // 过滤条件 match(Criteria.where("createdDate").gt(LocalDate.now().minusDays(range)) .and("transactionAction").is("GIFT")), // 按创建时间降序,确保最新交易优先 sort(Sort.Direction.DESC, "createdDate"), // 按userId分组,统计总积分并取最新的awardForContentId group("userId") .sum("transactionAmount").as("totalValueAwarded") .first("awardForContentId").as("awardForContentId"), // 分页逻辑 skip((long) pageable.getPageNumber() * pageable.getPageSize()), limit(pageable.getPageSize()) ); List<RecentlyRewardedUsers> results = mongoTemplate.aggregate(agg, Transaction.class, RecentlyRewardedUsers.class).getMappedResults();
内容的提问来源于stack exchange,提问作者MetaCoder
相关产品推荐
相关产品推荐

