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

如何通过Spring Data MongoDB获取MongoDB中的指定嵌套对象?

如何通过Spring Data MongoDB Repository直接获取嵌套对象

当然可以!Spring Data MongoDB提供了多种方式直接获取嵌套的子分类、品牌或产品对象,不用再手动迭代。先结合你提供的文档和实体类,给你详细介绍几种实用的方法:


先回顾你的基础信息

示例MongoDB文档

{ 
  "_id" : "a9582f59-f52b-4fc8-84ab-cdd0bfb8dead", 
  "_class" : "com.db.Category", 
  "name" : "Cricket", 
  "subCategories" : [ 
    { 
      "name" : "Gloves", 
      "creationDate" : NumberLong("1527404341099"), 
      "modificationDate" : NumberLong("1527404341099") 
    }, 
    { 
      "name" : "Stumps", 
      "creationDate" : NumberLong("1527404369882"), 
      "modificationDate" : NumberLong("1527404369882") 
    }, 
    { 
      "name" : "Bat", 
      "brandList" : [ 
        { 
          "name" : "MRF", 
          "productDetails" : [ 
            { 
              "name" : "Bat 111", 
              "price" : "1224", 
              "imageUrlList" : [ 
                "https://s3.us-east-1.amazonaws.com/gasports/1527792222680-Bat_111", 
                "https://s3.us-east-1.amazonaws.com/gasports/1527792228375-Bat_111" 
              ] 
            } 
          ] 
        } 
      ], 
      "creationDate" : NumberLong("1527424021629"), 
      "modificationDate" : NumberLong("1527424021629") 
    } 
  ], 
  "creationDate" : NumberLong("1527404340938"), 
  "modificationDate" : NumberLong("1527404340938") 
}

实体类定义

@Document(collection="productInfo") 
public class Category extends BaseProductInfo<Category> { 
    @Id 
    private String uid; 
    private String name; 
    private List<SubCategory> subCategories; 

    // Getters and setters..
}

方法1:用Spring Data查询方法命名规则快速实现

Spring Data支持通过方法名自动生成查询,针对嵌套对象,直接用点符号引用嵌套字段即可。

比如要获取指定分类下的某个子分类:

public interface CategoryRepository extends MongoRepository<Category, String> {
    // 根据子分类名称获取匹配的子分类列表
    List<SubCategory> findBySubCategoriesName(String subCategoryName);
    
    // 更精准:指定分类ID+子分类名称
    List<SubCategory> findByUidAndSubCategoriesName(String categoryId, String subCategoryName);
}

⚠️ 注意:这种方式会先查询整个Category文档,再从中提取匹配的子分类。如果文档体积很大,效率会稍低。

方法2:用@Query注解自定义高效查询

通过@Query编写原生MongoDB查询,配合投影(projection)只返回需要的嵌套对象,能大幅减少数据传输量,效率更高。

获取指定子分类

public interface CategoryRepository extends MongoRepository<Category, String> {
    @Query(value = "{ '_id' : ?0, 'subCategories.name' : ?1 }", fields = "{ 'subCategories.$' : 1 }")
    Category findSubCategoryByCategoryIdAndSubCategoryName(String categoryId, String subCategoryName);
}

这里的subCategories.$表示只返回第一个匹配的子分类(如果有多个同名子分类,只会取第一个)。返回的Category对象中,只有匹配的那个subCategories元素会被填充,其他字段为空或默认值。

获取指定品牌

针对更深层的品牌,继续嵌套点符号即可:

@Query(value = "{ '_id' : ?0, 'subCategories.name' : ?1, 'subCategories.brandList.name' : ?2 }", 
       fields = "{ 'subCategories.$.brandList.$' : 1 }")
Category findBrandByCategoryIdSubCategoryNameAndBrandName(String categoryId, String subCategoryName, String brandName);

获取指定产品

同理,获取最内层的产品:

@Query(value = "{ '_id' : ?0, 'subCategories.name' : ?1, 'subCategories.brandList.name' : ?2, 'subCategories.brandList.productDetails.name' : ?3 }", 
       fields = "{ 'subCategories.$.brandList.$.productDetails.$' : 1 }")
Category findProductByCategoryIdSubCategoryNameBrandNameAndProductName(String categoryId, String subCategoryName, String brandName, String productName);

方法3:用Projection接口直接返回嵌套对象

如果不想处理整个Category对象,只想拿到纯净的嵌套对象,可以定义Projection接口来提取需要的字段:

// 子分类投影
public interface SubCategoryProjection {
    String getName();
    Long getCreationDate();
    Long getModificationDate();
    List<BrandProjection> getBrandList();
}

// 品牌投影
public interface BrandProjection {
    String getName();
    List<ProductProjection> getProductDetails();
}

// 产品投影
public interface ProductProjection {
    String getName();
    String getPrice();
    List<String> getImageUrlList();
}

然后在Repository中使用:

public interface CategoryRepository extends MongoRepository<Category, String> {
    @Query(value = "{ '_id' : ?0, 'subCategories.name' : ?1 }", fields = "{ 'subCategories.$' : 1 }")
    SubCategoryProjection findSubCategoryProjectionByCategoryIdAndSubCategoryName(String categoryId, String subCategoryName);
}

这样返回的就是直接的SubCategoryProjection对象,无需再从Category中手动提取。

方法4:用Aggregation聚合查询处理复杂场景

如果需要返回所有匹配的嵌套元素(而不是第一个),或者有更复杂的筛选逻辑,推荐用MongoDB的Aggregation框架,通过MongoTemplate执行:

比如,获取某个分类下名为"Bat"的子分类中的所有品牌:

@Autowired
private MongoTemplate mongoTemplate;

public List<Brand> getBrandsFromSubCategory(String categoryId, String subCategoryName) {
    Aggregation aggregation = Aggregation.newAggregation(
        // 匹配指定分类
        Aggregation.match(Criteria.where("_id").is(categoryId)),
        // 展开子分类数组
        Aggregation.unwind("subCategories"),
        // 匹配目标子分类
        Aggregation.match(Criteria.where("subCategories.name").is(subCategoryName)),
        // 展开品牌数组
        Aggregation.unwind("subCategories.brandList"),
        // 只保留品牌字段
        Aggregation.project("subCategories.brandList").andExclude("_id"),
        // 将品牌对象作为根返回
        Aggregation.replaceRoot("subCategories.brandList")
    );
    
    AggregationResults<Brand> results = mongoTemplate.aggregate(aggregation, "productInfo", Brand.class);
    return results.getMappedResults();
}

这种方式灵活性极高,能处理多层嵌套的复杂查询需求。


总结

  • 简单场景(单个匹配对象):用@Query结合投影或查询方法命名就足够方便。
  • 需要返回所有匹配元素或复杂逻辑:用Aggregation聚合查询。
  • 想直接获取纯净的嵌套对象:用Projection接口。

内容的提问来源于stack exchange,提问作者Vipul Pachauri

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:05:56