Spring Boot中使用MongoTemplate排除嵌套对象数组指定字段
解决办法
给你三种可行的方案,按需选择:
方案一:接口投影(最简洁)
利用Spring Data MongoDB的接口投影可以直接实现嵌套字段的筛选,而且天然返回数组形式。
- 先定义NestedClass的投影接口,只保留需要的字段:
public interface NestedProjection { String getId(); String getName(); }
- 再定义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(); }
- 在你的DemoRepository里直接使用这个投影查询:
public interface DemoRepository extends MongoRepository<DemoClass, String> { List<DemoProjection> findAll(); }
调用这个方法时,MongoDB会自动只返回NestedClass的id和name字段,且list_of_it是数组形式。
方案二:DTO类+构造函数投影
如果需要更灵活的字段控制(比如重命名字段),可以用DTO类配合构造函数投影:
- 定义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; } }
- 定义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方法 }
- 在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的关联和字段映射。正确的聚合步骤应该是:
- 用
$lookup关联NestedClass集合(因为@DBRef实际存储的是引用ID,需要手动关联); - 用
$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
相关产品推荐
相关产品推荐

