Spring Boot集成MongoDB如何将嵌套数组字段提取为值数组
解决方案
有三种常用实现方式,可根据你的业务场景选择:
方案1:MongoDB聚合查询直接返回目标结构(推荐,数据库层面处理性能更高)
通过MongoDB的$map聚合操作直接提取嵌套数组的指定字段,无需后续Java代码转换:
// 自定义接收结果的DTO public class AssignmentResp { private String title; private List<String> docs; // 补全getter、setter方法 } // Repository层聚合查询实现 public List<AssignmentResp> getAssignments(final String uID) { MatchOperation matchOp = Aggregation.match( Criteria.where(CREATEDBY).is(uID) .orOperator( Criteria.where("docs.0").exists(true), Criteria.where("versionchecked").is(true) ) ); ProjectionOperation projectOp = Aggregation.project("title") .and(ArrayOperators.Map.arrayOf("docs") .as("docItem") .andApply(DocumentExpression.parse("$$docItem.fileId")) ).as("docs"); Aggregation aggregation = Aggregation.newAggregation(matchOp, projectOp); return mongoTemplate.aggregate(aggregation, "assignemnt", AssignmentResp.class).getMappedResults(); }
方案2:业务层手动转换结果(改造成本最低,不修改原有查询逻辑)
保留你现有查询逻辑,在返回给接口前通过Stream流提取字段转换为目标结构:
// 先定义返回用的DTO public class AssignmentResp { private String title; private List<String> docs; // 补全getter、setter方法 } // 业务层转换逻辑 List<Assignment> originList = assignmentRepository.getAssignments(uID); List<AssignmentResp> respList = originList.stream().map(origin -> { AssignmentResp resp = new AssignmentResp(); resp.setTitle(origin.getTitle()); List<String> fileIdList = origin.getDocs().stream() .map(Docs::getFileId) .toList(); resp.setDocs(fileIdList); return resp; }).toList();
方案3:Jackson自定义序列化(无侵入,无需修改业务和查询代码)
如果仅需要接口返回时自动转换,其他场景仍需要保留原有List<Docs>结构,可以通过Jackson序列化注解实现:
- 自定义序列化器
public class DocsToFileIdSerializer extends JsonSerializer<List<Docs>> { @Override public void serialize(List<Docs> docs, JsonGenerator gen, SerializerProvider serializers) throws IOException { List<String> fileIds = docs.stream().map(Docs::getFileId).toList(); gen.writeObject(fileIds); } }
- 在Assignment类的docs字段上加注解
@JsonSerialize(using = DocsToFileIdSerializer.class) private List<Docs> docs;
内容的提问来源于stack exchange,提问作者Kaveen M.
相关产品推荐
相关产品推荐

