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

Spring Boot中使用MongoTemplate排除嵌套对象数组指定字段

解决办法

给你三种可行的方案,按需选择:

方案一:接口投影(最简洁)

利用Spring Data MongoDB的接口投影可以直接实现嵌套字段的筛选,而且天然返回数组形式。

  1. 先定义NestedClass的投影接口,只保留需要的字段:
public interface NestedProjection {
    String getId();
    String getName();
}
  1. 再定义DemoClass的投影接口,包含自身需要的所有字段,以及嵌套的NestedProjection列表:
public interface DemoProjection {
    String getId();
    String getName();
    String getDescription();
    Long getCts();
    Long getMts();
    boolean isFavourite();
    String getCreatedBy();
    String getModifiedBy();
    List<NestedProjection> getList_of_it();
    List<Test> getTests(); // 如果Tests也需要投影,同理定义TestProjection
    List<String> getOrder();
}
  1. 在你的DemoRepository里直接使用这个投影查询:
public interface DemoRepository extends MongoRepository<DemoClass, String> {
    List<DemoProjection> findAll();
}

调用这个方法时,MongoDB会自动只返回NestedClass的id和name字段,且list_of_it是数组形式。

方案二:DTO类+构造函数投影

如果需要更灵活的字段控制(比如重命名字段),可以用DTO类配合构造函数投影:

  1. 定义NestedDTO:
public class NestedDTO {
    private String id;
    private String name;

    public NestedDTO(String id, String name) {
        this.id = id;
        this.name = name;
    }

    // getter方法
    public String getId() { return id; }
    public String getName() { return name; }
}
  1. 定义DemoDTO:
public class DemoDTO {
    private String id;
    private String name;
    private String description;
    private Long cts;
    private Long mts;
    private boolean favourite;
    private String createdBy;
    private String modifiedBy;
    private List<NestedDTO> list_of_it;
    private List<Test> tests;
    private List<String> order;

    // 构造函数要包含所有需要的字段,嵌套的List<NestedDTO>也直接传入
    public DemoDTO(String id, String name, String description, Long cts, Long mts, boolean favourite, String createdBy, String modifiedBy, List<NestedDTO> list_of_it, List<Test> tests, List<String> order) {
        this.id = id;
        this.name = name;
        this.description = description;
        this.cts = cts;
        this.mts = mts;
        this.favourite = favourite;
        this.createdBy = createdBy;
        this.modifiedBy = modifiedBy;
        this.list_of_it = list_of_it;
        this.tests = tests;
        this.order = order;
    }

    // 所有字段的getter方法
}
  1. 在Repository里用@Query指定投影字段:
public interface DemoRepository extends MongoRepository<DemoClass, String> {
    @Query(value = "{}", fields = "{ 'id': 1, 'name': 1, 'description': 1, 'cts': 1, 'mts': 1, 'favourite': 1, 'createdBy': 1, 'modifiedBy': 1, 'list_of_it.id': 1, 'list_of_it.name': 1, 'tests': 1, 'order': 1 }")
    List<DemoDTO> findAllProjectedBy();
}

这里通过fields参数明确指定要返回的字段,包括NestedClass的id和name。

方案三:聚合管道(适合复杂场景)

如果之前用聚合没成功,可能是没处理好@DBRef的关联和字段映射。正确的聚合步骤应该是:

  1. 用$lookup关联NestedClass集合(因为@DBRef实际存储的是引用ID,需要手动关联);
  2. 用$project配合$map筛选NestedClass的字段。

代码示例:

@Service
public class DemoService {
    @Autowired
    private MongoTemplate mongoTemplate;

    public List<DemoClass> findAllWithNestedProjection() {
        Aggregation aggregation = Aggregation.newAggregation(
            // 关联NestedClass集合,将list_of_it的ID转换成实际文档
            Aggregation.lookup("nestedClass", "list_of_it", "_id", "list_of_it"),
            // 投影筛选字段,对list_of_it只保留id和name
            Aggregation.project()
                .andInclude("id", "name", "description", "cts", "mts", "favourite", "createdBy", "modifiedBy", "tests", "order")
                .and(AggregationExpression.fromMongoExpression("{$map: {input: '$list_of_it', as: 'item', in: {id: '$$item._id', name: '$$item.name'}}}")).as("list_of_it")
        );

        return mongoTemplate.aggregate(aggregation, "demoClass", DemoClass.class).getMappedResults();
    }
}

注意:这里的集合名nestedClass和demoClass要和MongoDB中实际的集合名一致(通常是实体类名小写)。$map用来遍历list_of_it数组,只提取_id(对应Java的id)和name字段。


内容的提问来源于stack exchange,提问作者Madhusudan Tripathy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 17:42:37