sql >> Databáze >  >> NoSQL >> MongoDB

Spring Data MongoDB:Projekce a agregace

1. Přehled

Spring Data MongoDB poskytuje jednoduché abstrakce na vysoké úrovni do nativního dotazovacího jazyka MongoDB. V tomto článku prozkoumáme podporu pro projekce a agregační rámec.

Pokud s tímto tématem začínáte, podívejte se na náš úvodní článek Úvod do Spring Data MongoDB.

2. Projekce

V MongoDB jsou projekce způsob, jak z databáze načíst pouze požadovaná pole dokumentu. To snižuje množství dat, která je třeba přenášet z databázového serveru na klienta, a tudíž zvyšuje výkon.

S Spring Data MongDB lze projekce použít jak s MongoTemplate a MongoRepository.

Než se přesuneme dále, podívejme se na datový model, který budeme používat:

@Document
public class User {
    @Id
    private String id;
    private String name;
    private Integer age;
    
    // standard getters and setters
}

2.1. Projekce pomocí MongoTemplate

include() a exclude() metody v Poli class se používá k zahrnutí a vyloučení polí:

Query query = new Query();
query.fields().include("name").exclude("id");
List<User> john = mongoTemplate.find(query, User.class);

Tyto metody mohou být zřetězeny, aby zahrnovaly nebo vylučovaly více polí. Pole označené jako @Id (_id v databázi) je vždy načten, pokud není výslovně vyloučen.

Vyloučená pole jsou null v instanci třídy modelu, když jsou záznamy načteny s projekcí. V případě, že jsou pole primitivního typu nebo jejich obalové třídy, pak hodnoty vyloučených polí jsou výchozí hodnoty primitivních typů.

Například Řetězec bude null , int /Celé číslo bude 0 a logická /Boolean bude nepravda .

Ve výše uvedeném příkladu tedy name pole by bylo Jan , id bude null a věk bude 0.

2.2. Projekce pomocí MongoRepository

Při používání MongoRepositories pole z @Query anotaci lze definovat ve formátu JSON:

@Query(value="{}", fields="{name : 1, _id : 0}")
List<User> findNameAndExcludeId();

Výsledek by byl stejný jako při použití MongoTemplate. value=”{}” označuje žádné filtry, a proto budou načteny všechny dokumenty.

3. Agregace

Agregace v MongoDB byla vytvořena tak, aby zpracovávala data a vracela vypočítané výsledky. Data se zpracovávají po etapách a výstup z jedné etapy je poskytován jako vstup do další etapy. Tato schopnost aplikovat transformace a provádět výpočty na datech po etapách dělá z agregace velmi výkonný nástroj pro analýzu.

Spring Data MongoDB poskytuje abstrakci pro nativní agregační dotazy pomocí tří tříd Aggregation který obaluje agregační dotaz, AggregationOperation který obaluje jednotlivé fáze potrubí a AggregationResults což je kontejner výsledku vytvořeného agregací.

Chcete-li provést a agregovat, nejprve vytvořte agregační kanály pomocí metod statického sestavovače na Agregaci třídy a poté vytvořte instanci Aggregation pomocí newAggregation() metodou Agregace třídy a nakonec spusťte agregaci pomocí MongoTemplate :

MatchOperation matchStage = Aggregation.match(new Criteria("foo").is("bar"));
ProjectionOperation projectStage = Aggregation.project("foo", "bar.baz");
        
Aggregation aggregation 
  = Aggregation.newAggregation(matchStage, projectStage);

AggregationResults<OutType> output 
  = mongoTemplate.aggregate(aggregation, "foobar", OutType.class);

Upozorňujeme, že obě MatchOperation a Projekční operace implementovat AggregationOperation . Existují podobné implementace pro další agregační kanály. OutType je datový model pro očekávaný výstup.

Nyní se podíváme na několik příkladů a jejich vysvětlení, abychom pokryli hlavní agregační kanály a operátory.

Datový soubor, který budeme používat v tomto článku, uvádí podrobnosti o všech PSČ v USA, které lze stáhnout z úložiště MongoDB.

Podívejme se na vzorový dokument po jeho importu do kolekce s názvem zips v testu databáze.

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

V zájmu jednoduchosti a stručnosti kódu budeme v dalších fragmentech kódu předpokládat, že všechny statické metody agregace třídy jsou staticky importovány.

3.1. Získejte objednávky ve všech státech s populací větším než 10 milionů podle sestupné populace

Zde budeme mít tři potrubí:

  1. $group etapa shrnující populaci všech PSČ
  2. $match fázi k odfiltrování států s populací nad 10 milionů
  3. $sort fázi seřadit všechny dokumenty v sestupném pořadí podle počtu obyvatel

Očekávaný výstup bude mít pole _id jako stav a pole statePop s celkovým počtem obyvatel státu. Vytvoříme pro to datový model a spustíme agregaci:

public class StatePoulation {
 
    @Id
    private String state;
    private Integer statePop;
 
    // standard getters and setters
}

@Id anotace bude mapovat _id pole z výstupu do stavu v modelu:

GroupOperation groupByStateAndSumPop = group("state")
  .sum("pop").as("statePop");
MatchOperation filterStates = match(new Criteria("statePop").gt(10000000));
SortOperation sortByPopDesc = sort(Sort.by(Direction.DESC, "statePop"));

Aggregation aggregation = newAggregation(
  groupByStateAndSumPop, filterStates, sortByPopDesc);
AggregationResults<StatePopulation> result = mongoTemplate.aggregate(
  aggregation, "zips", StatePopulation.class);

AggregationResults třída implementuje Iterable a proto to můžeme iterovat a vytisknout výsledky.

Pokud výstupní datový model není znám, použijte standardní třídu MongoDB Document lze použít.

3.2. Získejte nejmenší stát podle průměrného počtu obyvatel města

Pro tento problém budeme potřebovat čtyři fáze:

  1. $group sečíst celkový počet obyvatel každého města
  2. $group vypočítat průměrnou populaci každého státu
  3. $sort stavy od fáze k pořadí podle jejich průměrné městské populace ve vzestupném pořadí
  4. $limit získat první stát s nejnižší průměrnou populací města

Ačkoli to není nezbytně nutné, použijeme další $project fázi přeformátování dokumentu podle StatePopulation datový model.

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

Aggregation aggregation = newAggregation(
  sumTotalCityPop, averageStatePop, sortByAvgPopAsc,
  limitToOnlyFirstDoc, projectToMatchModel);

AggregationResults<StatePopulation> result = mongoTemplate
  .aggregate(aggregation, "zips", StatePopulation.class);
StatePopulation smallestState = result.getUniqueMappedResult();

V tomto příkladu již víme, že ve výsledku bude pouze jeden dokument, protože v poslední fázi omezíme počet výstupních dokumentů na 1. Jako takové můžeme vyvolat getUniqueMappedResult() k získání požadované StatePopulation instance.

Další věc, kterou je třeba si všimnout, je, že namísto spoléhání se na @Id anotace k mapě _id konstatovat, že jsme to výslovně provedli ve fázi projekce.

3.3. Získejte stát s maximálním a minimálním PSČ

Pro tento příklad potřebujeme tři fáze:

  1. $group spočítat počet PSČ pro každý stát
  2. $sort seřadit státy podle počtu PSČ
  3. $group k nalezení státu s maximálním a minimálním PSČ pomocí $first a $last operátory
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");

Aggregation aggregation = newAggregation(sumZips, sortByCount, groupFirstAndLast);

AggregationResults<Document> result = mongoTemplate
  .aggregate(aggregation, "zips", Document.class);
Document document= result.getUniqueMappedResult();

Zde jsme nepoužili žádný model, ale použili jsme Dokument již dodáván s ovladačem MongoDB.


  1. Max a min v mongodb

  2. Mongodb:Nepodařilo se připojit k 127.0.0.1:27017, důvod:errno:10061

  3. Nelze se připojit k redis pomocí jedis

  4. Získejte index položky podle hodnoty v seznamu redis