MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Restituisce solo campi specifici per una query in Spring Data MongoDB

1. Panoramica

Quando si utilizza Spring Data MongoDB, potrebbe essere necessario limitare le proprietà mappate da un oggetto database. In genere, potremmo averne bisogno, ad esempio, per motivi di sicurezza, per evitare di esporre informazioni riservate archiviate su un server. Oppure, ad esempio, potremmo dover filtrare parte dei dati visualizzati in un'applicazione web.

In questo breve tutorial, vedremo come MongoDB applica la restrizione dei campi.

2. Limitazione dei campi MongoDB mediante proiezione

MongoDB utilizza Projection per specificare o limitare i campi da restituire da una query . Tuttavia, se utilizziamo Spring Data, vogliamo applicarlo con MongoTemplate o MongoRepository .

Pertanto, vogliamo creare casi di test per entrambi MongoTemplate e MongoRepository dove possiamo applicare restrizioni sul campo.

3. Implementazione della proiezione

3.1. Configurazione dell'entità

Innanzitutto, creiamo un Inventario classe:

@Document(collection = "inventory")
public class Inventory {

    @Id
    private String id;
    private String status;
    private Size size;
    private InStock inStock;

    // standard getters and setters    
}

3.2. Configurazione del repository

Quindi, per testare MongoRepository , creiamo un InventoryRepository . Useremo anche un dove condizione con @Query . Ad esempio, vogliamo filtrare lo stato dell'inventario:

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);

}

3.3. Aggiunta delle dipendenze Maven

Utilizzeremo anche Embedded MongoDB. Aggiungiamo spring-data-mongodb e de.flapdoodle.embed.mongo dipendenze dal nostro pom.xml file:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-mongodb</artifactId>
    <version>3.0.3.RELEASE</version>
</dependency>
<dependency>
    <groupId>de.flapdoodle.embed</groupId>
    <artifactId>de.flapdoodle.embed.mongo</artifactId>
    <version>3.2.6</version>
    <scope>test</scope>
</dependency>

4. Prova utilizzando MongoRepository e Modello Mongo

Per MongoRepository , vedremo esempi utilizzando @Query e applicando la restrizione sul campo, mentre per MongoTemplate , utilizzeremo il  Interrogazione  classe.

Cercheremo di coprire tutte le diverse combinazioni di inclusione ed esclusione. In particolare, vedremo come limitare i campi incorporati o, cosa più interessante, gli array usando la fetta proprietà .

Per ogni test, aggiungeremo il MongoRepository prima l'esempio, seguito da quello per MongoTemplate .

4.1. Includi solo campi

Iniziamo includendo alcuni campi. Tutti gli esclusi saranno nulli . La proiezione aggiunge l'_id per impostazione predefinita:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getId());
  assertNotNull(i.getItem());
  assertNotNull(i.getStatus());
  assertNull(i.getSize());
  assertNull(i.getInStock());
});

Ora, diamo un'occhiata al MongoTemplate versione:

Query query = new Query();
 query.fields()
   .include("item")
   .include("status");

4.2. Includi ed escludi campi

Questa volta, vedremo esempi che includono esplicitamente alcuni campi ma ne escludono altri:in questo caso, escluderemo l'_id campo:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusExcludeIdFields("A");

inventoryList.forEach(i -> {
   assertNotNull(i.getItem());
   assertNotNull(i.getStatus());
   assertNull(i.getId());
   assertNull(i.getSize());
   assertNull(i.getInStock());
});

La query equivalente che utilizza MongoTemplate sarebbe:

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .exclude("_id");

4.3. Escludi solo campi

Continuiamo escludendo alcuni campi. Tutti gli altri campi non saranno nulli:

List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");

inventoryList.forEach(i -> {
  assertNotNull(i.getItem());
  assertNotNull(i.getId());
  assertNotNull(i.getSize());
  assertNull(i.getInStock());
  assertNull(i.getStatus());
});

E, diamo un'occhiata al MongoTemplate versione:

Query query = new Query();
query.fields()
  .exclude("status")
  .exclude("inStock");

4.4. Includi campi incorporati

Anche in questo caso, l'inclusione dei campi incorporati li aggiungerà al nostro risultato:

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());
});

Vediamo come fare lo stesso con MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("size.uom");

4.5. Escludi campi incorporati

Allo stesso modo, escludere i campi incorporati li tiene fuori dal nostro risultato, tuttavia, aggiungerebbe il resto dei campi incorporati :

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());
});

Diamo un'occhiata al MongoTemplate versione:

Query query = new Query();
query.fields()
  .exclude("size.uom");

4.6. Includi campi incorporati nell'array

Analogamente ad altri campi, possiamo anche aggiungere una proiezione del campo di un array:

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());
});

Implementiamo lo stesso usando MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .include("inStock.quantity");

4.7. Includi i campi incorporati nell'array usando slice

MongoDB può utilizzare le funzioni JavaScript per limitare i risultati di un array, ad esempio ottenendo solo l'ultimo elemento in un array usando 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());
});

Eseguiamo la stessa query utilizzando MongoTemplate :

Query query = new Query();
query.fields()
  .include("item")
  .include("status")
  .slice("inStock", -1);