Spring Data MongoDB: projecties en aggregaties

1. Overzicht

Spring Data MongoDB biedt eenvoudige abstracties op hoog niveau voor de native querytaal van MongoDB. In dit artikel, we zullen de ondersteuning voor Projections and Aggregation-raamwerk onderzoeken.

Als u nieuw bent bij dit onderwerp, raadpleegt u ons inleidende artikel Inleiding tot Spring Data MongoDB.

2. Projectie

In MongoDB zijn projecties een manier om alleen de vereiste velden van een document uit een database op te halen. Dit vermindert de hoeveelheid gegevens die van de databaseserver naar de client moet worden overgebracht en verhoogt dus de prestaties.

Met Spring Data MongDB kunnen projecties beide worden gebruikt met MongoTemplate en MongoRepository.

Laten we, voordat we verder gaan, kijken naar het datamodel dat we zullen gebruiken:

@Document openbare klasse Gebruiker {@Id privé String-id; private String naam; privé Integer leeftijd; // standaard getters en setters}

2.1. Projecties gebruiken MongoTemplate

De omvatten () en uitsluiten() methoden op de Veld klasse wordt gebruikt om respectievelijk velden op te nemen en uit te sluiten:

Queryquery = nieuwe Query (); query.fields (). include ("naam"). exclude ("id"); Lijst john = mongoTemplate.find (query, User.class);

Deze methoden kunnen aan elkaar worden gekoppeld om meerdere velden op te nemen of uit te sluiten. Het veld gemarkeerd als @ID kaart (_ID kaart in de database) wordt altijd opgehaald, tenzij expliciet uitgesloten.

Uitgesloten velden zijn nul in de modelklasse-instantie wanneer records worden opgehaald met projectie. In het geval dat velden van een primitief type zijn of hun wrapper-klasse, dan is de waarde van uitgesloten velden de standaardwaarden van de primitieve typen.

Bijvoorbeeld, Draad zou zijn nul, int/Geheel getal zou zijn 0 en boolean/Boolean zou zijn false.

Dus in het bovenstaande voorbeeld is de naam veld zou zijn John, ID kaart zou zijn nul en leeftijd zou zijn 0.

2.2. Projecties gebruiken MongoRepository

Tijdens het gebruik van MongoRepositories kan de velden van @Query annotatie kan worden gedefinieerd in JSON-indeling:

@Query (waarde = "{}", fields = "{naam: 1, _id: 0}") Lijst findNameAndExcludeId ();

Het resultaat zou hetzelfde zijn als het gebruik van de MongoTemplate. De value = "{}" geeft geen filters aan en daarom worden alle documenten opgehaald.

3. Aggregatie

Aggregatie in MongoDB is gebouwd om gegevens te verwerken en berekende resultaten te retourneren. De gegevens worden in fasen verwerkt en de uitvoer van de ene fase wordt geleverd als invoer voor de volgende fase. Dit vermogen om transformaties toe te passen en berekeningen op gegevens in fasen uit te voeren, maakt aggregatie tot een zeer krachtig hulpmiddel voor analyses.

Spring Data MongoDB biedt een abstractie voor native aggregatiequery's met behulp van de drie klassen Aggregatie die een aggregatiequery omhult, AggregationOperation die individuele pijplijnfasen omwikkelt en Aggregatieresultaten dat is de container van het resultaat geproduceerd door aggregatie.

Om uit te voeren en aggregatie te maken, moet u eerst aggregatiepijplijnen maken met behulp van de statische opbouwmethoden op Aggregatie class en maak vervolgens een instantie van Aggregatie de ... gebruiken newAggregation () methode op de Aggregatie class en voer tenslotte de aggregatie uit met MongoTemplate:

MatchOperation matchStage = Aggregation.match (nieuwe criteria ("foo"). Is ("bar")); ProjectionOperation projectStage = Aggregation.project ("foo", "bar.baz"); Aggregation aggregation = Aggregation.newAggregation (matchStage, projectStage); AggregationResults output = mongoTemplate.aggregate (aggregatie, "foobar", OutType.class);

Houd er rekening mee dat beide MatchOperation en ProjectieWerking implementeren AggregationOperation. Er zijn vergelijkbare implementaties voor andere aggregatiepijplijnen. OutType is het datamodel voor verwachte output.

Nu zullen we een paar voorbeelden en hun uitleg bekijken voor de belangrijkste aggregatiepijpleidingen en operators.

De dataset die we in dit artikel zullen gebruiken, bevat details over alle postcodes in de VS die kunnen worden gedownload van de MongoDB-repository.

Laten we eens kijken naar een voorbeelddocument nadat we het hebben geïmporteerd in een verzameling met de naam ritsen in de test database.

{"_id": "01001", "city": "AGAWAM", "loc": [-72.622739, 42.070206], "pop": 15338, "state": "MA"}

Omwille van de eenvoud en om de code beknopt te houden, gaan we in de volgende codefragmenten ervan uit dat alle statisch methodes van Aggregatie klasse worden statisch geïmporteerd.

3.1. Verkrijg alle staten met een bevolking van meer dan 10 miljoen Orde per aflopend aantal inwoners

Hier hebben we drie pijpleidingen:

  1. $ groep fase waarin de populatie van alle postcodes wordt samengevat
  2. $ match fase om staten met een bevolking van meer dan 10 miljoen uit te filteren
  3. $ sort fase om alle documenten in aflopende volgorde van populatie te sorteren

De verwachte uitvoer heeft een veld _ID kaart als staat en een veld statePop met de totale staatsbevolking. Laten we hiervoor een datamodel maken en de aggregatie uitvoeren:

openbare klasse StatePoulation {@Id private String state; privé Geheel getal statePop; // standaard getters en setters}

De @ID kaart annotatie zal het _ID kaart veld van output naar staat in het model:

GroupOperation groupByStateAndSumPop = group ("state") .sum ("pop"). As ("statePop"); MatchOperation filterStates = match (nieuwe criteria ("statePop"). Gt (10000000)); SortOperation sortByPopDesc ​​= sort (Sort.by (Direction.DESC, "statePop")); Aggregatie-aggregatie = newAggregation (groupByStateAndSumPop, filterStates, sortByPopDesc); AggregationResults resultaat = mongoTemplate.aggregate (aggregatie, "zips", StatePopulation.class);

De Aggregatieresultaten klasse implementeert Herhaalbaar en daarom kunnen we het herhalen en de resultaten afdrukken.

Als het uitvoergegevensmodel niet bekend is, is de standaard MongoDB-klasse Document kan worden gebruikt.

3.2. Verkrijg de kleinste staat op basis van de gemiddelde stadsbevolking

Voor dit probleem hebben we vier fasen nodig:

  1. $ groep om de totale bevolking van elke stad op te tellen
  2. $ groep om de gemiddelde bevolking van elke staat te berekenen
  3. $ sort stap om staten te ordenen op basis van hun gemiddelde stadsbevolking in oplopende volgorde
  4. $ limiet om de eerste staat met de laagste gemiddelde stadsbevolking te krijgen

Hoewel het niet per se vereist is, zullen we een extra $ project fase om het document opnieuw te formatteren zoals beschreven Staat Bevolking datamodel.

GroupOperation sumTotalCityPop = group ("state", "city") .sum ("pop"). As ("cityPop"); GroupOperation averageStatePop = group ("_ id.state") .avg ("cityPop"). As ("avgCityPop"); SortOperation sortByAvgPopAsc = sort (Sort.by (Direction.ASC, "avgCityPop")); LimitOperation limitToOnlyFirstDoc = limit (1); ProjectionOperation projectToMatchModel = project () .andExpression ("_ id"). As ("state") .andExpression ("avgCityPop"). As ("statePop"); Aggregatie-aggregatie = newAggregation (sumTotalCityPop, averageStatePop, sortByAvgPopAsc, limitToOnlyFirstDoc, projectToMatchModel); AggregationResults resultaat = mongoTemplate .aggregate (aggregatie, "zips", StatePopulation.class); StatePopulation smallestState = result.getUniqueMappedResult ();

In dit voorbeeld weten we al dat er maar één document in het resultaat zal zijn, aangezien we het aantal uitvoerdocumenten beperken tot 1 in de laatste fase. Als zodanig kunnen we een beroep doen getUniqueMappedResult () om het vereiste te krijgen Staat Bevolking voorbeeld.

Een ander ding om op te merken is dat, in plaats van te vertrouwen op de @ID kaart annotatie op de kaart _ID kaart om te zeggen, we hebben het expliciet gedaan in de projectiefase.

3.3. Verkrijg de staat met maximale en minimale postcode

Voor dit voorbeeld hebben we drie fasen nodig:

  1. $ groep om het aantal postcodes voor elke staat te tellen
  2. $ sort om de staten te ordenen op het aantal postcodes
  3. $ groep om de staat met max en min postcode te vinden met $ eerst en $ laatste operators
GroupOperation sumZips = group ("state"). Count (). As ("zipCount"); SortOperation sortByCount = sort (Direction.ASC, "zipCount"); GroupOperation groupFirstAndLast = group (). First ("_ id"). As ("minZipState") .first ("zipCount"). As ("minZipCount"). Last ("_ id"). As ("maxZipState") .last ("zipCount"). as ("maxZipCount"); Aggregatie-aggregatie = newAggregation (sumZips, sortByCount, groupFirstAndLast); AggregationResults resultaat = mongoTemplate .aggregate (aggregatie, "zips", Document.class); Document document = result.getUniqueMappedResult ();

Hier hebben we geen enkel model gebruikt, maar de Document al voorzien van MongoDB-stuurprogramma.

4. Conclusie

In dit artikel hebben we geleerd hoe we gespecificeerde velden van een document in MongoDB kunnen ophalen met behulp van projecties in Spring Data MongoDB.

We leerden ook over de ondersteuning van het MongoDB-aggregatieframework in Spring Data. We behandelden de belangrijkste aggregatiefasen - groeperen, projecteren, sorteren, beperken en matchen en keken naar enkele voorbeelden van de praktische toepassingen ervan. De volledige broncode is beschikbaar op GitHub.