1. Présentation
Lors de l'utilisation de Spring Data MongoDB, nous devrons peut-être restreindre les propriétés mappées à partir d'un objet de base de données. En règle générale, nous pouvons en avoir besoin, par exemple, pour des raisons de sécurité - pour éviter d'exposer des informations sensibles stockées sur un serveur. Ou encore, par exemple, nous pouvons avoir besoin de filtrer une partie des données affichées dans une application Web.
Dans ce court tutoriel, nous verrons comment MongoDB applique la restriction de champ.
2. Restriction des champs MongoDB à l'aide de la projection
MongoDB utilise Projection pour spécifier ou restreindre les champs à renvoyer à partir d'une requête . Cependant, si nous utilisons Spring Data, nous voulons l'appliquer avec MongoTemplate ou MongoRepository .
Par conséquent, nous voulons créer des cas de test pour MongoTemplate et MongoRepository où nous pouvons appliquer des restrictions de champ.
3. Mise en œuvre de la projection
3.1. Configuration de l'entité
Commençons par créer un inventaire 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. Configuration du référentiel
Ensuite, pour tester MongoRepository , nous créons un InventoryRepository . Nous utiliserons également un où condition avec @Query . Par exemple, nous souhaitons filtrer l'état de l'inventaire :
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. Ajout des dépendances Maven
Nous utiliserons également Embedded MongoDB. Ajoutons le spring-data-mongodb et de.flapdoodle.embed.mongo dépendances à notre pom.xml fichier :
<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. Testez avec MongoRepository et MongoTemplate
Pour MongoRepository , nous verrons des exemples utilisant @Query et appliquer la restriction de champ, tandis que pour MongoTemplate , nous utiliserons Requête classe.
Nous essaierons de couvrir toutes les différentes combinaisons d'inclusion et d'exclusion. En particulier, nous verrons comment restreindre les champs intégrés ou, plus intéressant, les tableaux à l'aide de la slice propriété .
Pour chaque test, nous ajouterons le MongoRepository exemple en premier, suivi de celui pour MongoTemplate .
4.1. Inclure uniquement les champs
Commençons par inclure quelques champs. Tous les exclus seront null . La projection ajoute le _id par défaut :
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeItemAndStatusFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getId());
assertNotNull(i.getItem());
assertNotNull(i.getStatus());
assertNull(i.getSize());
assertNull(i.getInStock());
});
Maintenant, regardons le MongoTemplate version :
Query query = new Query();
query.fields()
.include("item")
.include("status");
4.2. Inclure et exclure des champs
Cette fois, nous verrons des exemples qui incluent explicitement certains champs mais en excluent d'autres - dans ce cas, nous exclurons le _id champ :
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 requête équivalente utilisant MongoTemplate serait :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.exclude("_id");
4.3. Exclure uniquement les champs
Continuons en excluant certains champs. Tous les autres champs seront non nuls :
List<Inventory> inventoryList = inventoryRepository.findByStatusIncludeAllButStatusAndStockFields("A");
inventoryList.forEach(i -> {
assertNotNull(i.getItem());
assertNotNull(i.getId());
assertNotNull(i.getSize());
assertNull(i.getInStock());
assertNull(i.getStatus());
});
Et, regardons le MongoTemplate version :
Query query = new Query();
query.fields()
.exclude("status")
.exclude("inStock");
4.4. Inclure les champs intégrés
Encore une fois, inclure des champs intégrés les ajoutera à notre résultat :
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());
});
Voyons comment faire de même avec MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("size.uom");
4.5. Exclure les champs intégrés
De même, l'exclusion des champs intégrés les exclut de notre résultat, cependant, cela ajouterait le reste des champs intégrés :
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());
});
Jetons un coup d'œil au MongoTemplate version :
Query query = new Query();
query.fields()
.exclude("size.uom");
4.6. Inclure les champs intégrés dans le tableau
Comme pour les autres champs, nous pouvons également ajouter une projection du champ d'un tableau :
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());
});
Implémentons la même chose en utilisant MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.include("inStock.quantity");
4.7. Inclure les champs intégrés dans le tableau à l'aide de slice
MongoDB peut utiliser des fonctions JavaScript pour limiter les résultats d'un tableau - par exemple, obtenir uniquement le dernier élément d'un tableau en utilisant 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());
});
Effectuons la même requête en utilisant MongoTemplate :
Query query = new Query();
query.fields()
.include("item")
.include("status")
.slice("inStock", -1);