• Spring Data MongoDB中查询指定返回特定字段


    1. 概述

    使用 Spring Data MongoDB时,我们可能需要限制从数据库对象映射的属性。通常,出于安全原因,我们可能需要这样做—以避免暴露存储在服务器上的敏感信息。或者,例如,我们可能需要过滤掉 Web 应用程序中显示的部分数据。

    在这个简短的教程中,我们将看到 MongoDB 如何应用字段限制。

    2. 使用 Projection 的 MongoDB 字段限制

    MongoDB 使用Projection来指定或限制从查询返回的字段。但是,如果我们使用 Spring Data,我们希望将其与MongoTemplateMongoRepository一起应用。

    因此,我们希望为MongoTemplateMongoRepository创建测试用例,我们可以在其中应用字段限制。

    3. 实施投影

    3.1. 设置实体

    首先,让我们创建一个Inventory类:

    @Document(collection = "inventory")
    public class Inventory {
    
        @Id
        private String id;
        private String status;
        private Size size;
        private InStock inStock;
    
        // standard getters and setters    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.2. 设置 Repository

    然后,为了测试MongoRepository,我们创建了一个InventoryRepository。我们还将在@Query中使用where条件。例如,我们要过滤库存状态:

    public interface InventoryRepository extends MongoRepository<Inventory, String> {
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1 }")
        List<Inventory> findByStatusIncludeItemAndStatusFields(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, '_id' : 0 }")
        List<Inventory> findByStatusIncludeItemAndStatusExcludeIdFields(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'status' : 0, 'inStock' : 0 }")
        List<Inventory> findByStatusIncludeAllButStatusAndStockFields(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'size.uom': 1 }")
        List<Inventory> findByStatusIncludeEmbeddedFields(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'size.uom': 0 }")
        List<Inventory> findByStatusExcludeEmbeddedFields(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'inStock.quantity': 1 }")
        List<Inventory> findByStatusIncludeEmbeddedFieldsInArray(String status);
    
        @Query(value = "{ 'status' : ?0 }", fields = "{ 'item' : 1, 'status' : 1, 'inStock': { $slice: -1 } }")
        List<Inventory> findByStatusIncludeEmbeddedFieldsLastElementInArray(String status);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    @Query里的value: ?0标识匹配方法的第一个参数,?1第二个参数

    3.3. 添加 Maven 依赖项

    我们还将使用嵌入式 MongoDB。让我们将 spring-data-mongodbde.flapdoodle.embed.mongo 依赖添加到我们的pom.xml文件中:

    <dependency>
        <groupId>org.springframework.datagroupId>
        <artifactId>spring-data-mongodbartifactId>
        <version>3.0.3.RELEASEversion>
    dependency>
    <dependency>
        <groupId>de.flapdoodle.embedgroupId>
        <artifactId>de.flapdoodle.embed.mongoartifactId>
        <version>3.2.6version>
        <scope>testscope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4. 使用MongoRepositoryMongoTemplate 进行测试

    对于MongoRepository,我们将看到使用@Query和应用字段限制(Field Restriction)的示例,而对于MongoTemplate, 我们将使用Query 类。

    我们将尝试涵盖包含和排除的所有不同组合。特别是,我们将看到如何限制嵌入字段,或者更有趣的是,使用slice属性限制数组。

    对于每个测试,我们将首先添加MongoRepository示例,然后添加MongoTemplate示例。

    4.1.仅包含字段

    让我们从包括一些字段开始。所有排除的都将为null。投影默认添加 _id

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getId());
      assertNotNull(i.getItem());
      assertNotNull(i.getStatus());
      assertNull(i.getSize());
      assertNull(i.getInStock());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    现在,让我们看看MongoTemplate版本:

    Query query = new Query();
     query.fields()
       .include("item")
       .include("status");
    
    • 1
    • 2
    • 3
    • 4

    4.2. 包括和排除字段

    这一次,我们将看到明确包含某些字段但排除其他字段的示例—在这种情况下,我们将排除*_id*字段:

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");
    
    inventoryList.forEach(i -> {
       assertNotNull(i.getItem());
       assertNotNull(i.getStatus());
       assertNull(i.getId());
       assertNull(i.getSize());
       assertNull(i.getInStock());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用MongoTemplate的等效查询将是:

    Query query = new Query();
    query.fields()
      .include("item")
      .include("status")
      .exclude("_id");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.3. 仅排除字段

    让我们继续排除一些字段。所有其他字段将是非空的:

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getItem());
      assertNotNull(i.getId());
      assertNotNull(i.getSize());
      assertNull(i.getInStock());
      assertNull(i.getStatus());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    而且,让我们看看MongoTemplate版本:

    Query query = new Query();
    query.fields()
      .exclude("status")
      .exclude("inStock");
    
    • 1
    • 2
    • 3
    • 4

    4.4. 包括嵌入字段

    同样,包含嵌入字段会将它们添加到我们的结果中:

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFields("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getItem());
      assertNotNull(i.getStatus());
      assertNotNull(i.getId());
      assertNotNull(i.getSize());
      assertNotNull(i.getSize().getUom());
      assertNull(i.getSize().getHeight());
      assertNull(i.getSize().getWidth());
      assertNull(i.getInStock());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    让我们看看如何对MongoTemplate做同样的事情:

    Query query = new Query();
    query.fields()
      .include("item")
      .include("status")
      .include("size.uom");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.5. 排除嵌入字段

    同样,排除嵌入字段会将它们排除在我们的结果之外,但是,它会添加其余的嵌入字段:

    List<Inventory> inventoryList = inventoryRepository.findByStatusExcludeEmbeddedFields("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getItem());
      assertNotNull(i.getStatus());
      assertNotNull(i.getId());
      assertNotNull(i.getSize());
      assertNull(i.getSize().getUom());
      assertNotNull(i.getSize().getHeight());
      assertNotNull(i.getSize().getWidth());
      assertNotNull(i.getInStock());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    我们来看看MongoTemplate版本:

    Query query = new Query();
    query.fields()
      .exclude("size.uom");
    
    • 1
    • 2
    • 3

    4.6. 在数组中包含嵌入字段

    与其他字段类似,我们也可以添加数组字段的投影:

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFieldsInArray("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getItem());
      assertNotNull(i.getStatus());
      assertNotNull(i.getId());
      assertNotNull(i.getInStock());
      i.getInStock()
        .forEach(stock -> {
          assertNull(stock.getWareHouse());
          assertNotNull(stock.getQuantity());
         });
      assertNull(i.getSize());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    让我们使用MongoTemplate实现相同的功能:

    Query query = new Query();
    query.fields()
      .include("item")
      .include("status")
      .include("inStock.quantity");
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.7. 使用 slice(切片) 在数组中包含嵌入字段

    MongoDB 可以使用 JavaScript 函数来限制数组的结果——例如,使用 slice 只获取数组中的最后一个元素:

    List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeEmbeddedFieldsLastElementInArray("A");
    
    inventoryList.forEach(i -> {
      assertNotNull(i.getItem());
      assertNotNull(i.getStatus());
      assertNotNull(i.getId());
      assertNotNull(i.getInStock());
      assertEquals(1, i.getInStock().size());
      assertNull(i.getSize());
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    让我们使用MongoTemplate执行相同的查询:

    Query query = new Query();
    query.fields()
      .include("item")
      .include("status")
      .slice("inStock", -1);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    5. 结论

    在本文中,我们研究了 Spring Data MongoDB 中的投影。

    我们已经看到了使用 字段 的示例,包括MongoRepository 接口和 @Query注释,以及MongoTemplateQuery 类。

  • 相关阅读:
    领导批评的点需改正
    力扣第1035题 不相交的线中等 c++ (最长公共子序列) 动态规划 附Java代码
    C语言结构体的存储空间分配
    防止鱼叉式网络钓鱼的4个步骤
    【租车骑绿道】python实现-附ChatGPT解析
    V4L2 Camera 开发
    多模态大语言模型综述(中)-算法实用指南
    linux批量修改文件名及文件内容
    MQ - 35 四款MQ的架构设计与实现的对比
    羽夏看Linux内核——中断与分页相关入门知识
  • 原文地址:https://blog.csdn.net/wjw465150/article/details/127799307