MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Spring Boot Data et MongoDB - Filtrer la requête de tableau de sous-documents

Eh bien, dans Spring Data, ce type de requêtes n'est pas trivial .

Mauvaise nouvelle :
Spring Data Repository n'a pas de solution pour MongoDB Aggregation . Ainsi, vous ne pouvez pas implémenter dans MongoRepository une méthode pour le faire, comme aggregateBy...

Bonne nouvelle :
Spring Data fournit MongoTemplate classe qui vous permet d'exécuter des requêtes complexes, comme vous le feriez dans le shell MongoDB standard.

Donc, comme vous voulez juste exclude sous-document qui ne correspond pas à certaines conditions, nous devons définir l'agrégat pipelines .

Je suppose :

zip codes are Numeric (In your example is string)
And, to exclude subdocument, we filter by `zip`
There is no any other filter

L'agrégation MongoDB serait :

db.person.aggregate([
    {$unwind: "$address"},
    {$match: {"address.zip": 12345}},
    {$group: { _id: { "firstName":"$firstName", "lastName":"$lastName", _id:"$_id" }, address: { $push: "$address" } } },
    {$project: {_id:0, "firstName":"$_id.firstName", "lastName":"$_id.lastName", "address": "$address"}}
])

Si tous les filtres réussissent, nous obtenons :

[ 
    {
        "address" : [ 
            {
                "zip" : 12345
            }, 
            {
                "zip" : 12345
            }
        ],
        "firstName" : "George",
        "lastName" : "Washington"
    }
]

Maintenant, à la manière de Spring Data, vous devez ajouter quelques modifications à votre projet :

Tout d'abord, trouvez votre mongo-config.xml où vous devez ajouter :

<!-- Define the mongoDbFactory with your database Name  -->
<mongo:db-factory uri="mongodb://user:[email protected]:27017/db"/>

<!-- Define the MongoTemplate  -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
    <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
</bean>

MongoTemplate est la classe centrale du support MongoDB de Spring fournissant des ensembles de fonctionnalités pour interagir avec la base de données. Le modèle ... fournit un mappage entre vos objets de domaine et Documents MongoDB . Plus d'infos

Deuxièmement, dans votre @Service class, ajoutez le code suivant à charger dans @PostConstruct

@Autowired
private MongoOperations mongoOperations;

...

public List<Person> findByAddressZipCode(int zip) {

    List<AggregationOperation> list = new ArrayList<AggregationOperation>();
    list.add(Aggregation.unwind("address"));
    list.add(Aggregation.match(Criteria.where("address.zip").is(zip)));
    list.add(Aggregation.group("firstName", "lastName").push("address").as("address"));
    list.add(Aggregation.project("firstName", "lastName", "address"));
    TypedAggregation<Person> agg = Aggregation.newAggregation(Person.class, list);
    return mongoOperations.aggregate(agg, Person.class, Person.class).getMappedResults();
}

Remarque : Les deux, Person et Address devrait avoir un constructeur vide par défaut !