Description
L'étape aggregate(...) calcule les résultats agrégés (par exemple, le nombre, la somme) à partir des documents renvoyés par l'étape précédente.
Éventuellement, lorsqu'une expression de regroupement est fournie, elle regroupe les documents en fonction des expressions fournies, puis applique des fonctions d'accumulateur à chaque groupe.
Exemples
Pour les agrégations sans regroupement, l'étape aggregate(...) prend une ou plusieurs expressions d'agrégateur avec alias :
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate(
countAll().as("total"),
average("population").as("avg_population")
)
.execute();
Pour les agrégations avec regroupement, elle prend des groupes supplémentaires en plus des agrégateurs :
Node.js
const result = await db.pipeline()
.collectionGroup('citites')
.aggregate({
accumulators: [
countAll().as('cities'),
field('population').sum().as('total_popoluation')
],
groups: [field('location.state').as('state')]
})
.execute();
Comportement
Agrégations sans regroupement
Créez une collection cities avec les documents suivants :
Node.js
await db.collection('cities').doc('SF').set({name: 'San Francisco', state: 'CA', country: 'USA', population: 870000});
await db.collection('cities').doc('LA').set({name: 'Los Angeles', state: 'CA', country: 'USA', population: 3970000});
await db.collection('cities').doc('NY').set({name: 'New York', state: 'NY', country: 'USA', population: 8530000});
await db.collection('cities').doc('TOR').set({name: 'Toronto', state: null, country: 'Canada', population: 2930000});
await db.collection('cities').doc('MEX').set({name: 'Mexico City', state: null, country: 'Mexico', population: 9200000});
Pour connaître le nombre total de villes et leur population moyenne :
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate(
countAll().as("total"),
average("population").as("avg_population")
)
.execute();
qui produit :
{avg_population: 5100000, total: 5}
Effectuer des agrégations sur des groupes
En fournissant un argument groups, vous pouvez effectuer des agrégations sur chaque groupe distinct.
Par exemple, pour trouver la ville la plus peuplée de chaque pays et de chaque État :
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate({
accumulators: [
countAll().as("number_of_cities"),
maximum("population").as("max_population")
],
groups: ["country", "state"]
})
.execute();
qui donne :
{country: "USA", state: "CA", max_population: 3970000, number_of_cities: 2},
{country: "USA", state: "NY", max_population: 8530000, number_of_cities: 1},
{country: "Canada", state: null, max_population: 2930000, number_of_cities: 1},
{country: "Mexico", state: null, max_population: 9200000, number_of_cities: 1}
Expressions complexes sur le regroupement
Au-delà du regroupement par valeurs de champ uniquement, l'étape aggregate(...) permet de regrouper les résultats d'expressions complexes. Toute expression valide dans
une select(...) étape peut être utilisée comme clé de regroupement.
Cela permet un regroupement flexible basé sur des valeurs ou des conditions calculées.
Par exemple, pour regrouper les données selon que le champ d'état est nul ou non, et pour connaître la population totale de chaque groupe :
Node.js
const cities = await db.pipeline()
.collection("/cities")
.aggregate({
accumulators: [
sum("population").as("total_population")
],
groups: [equal(field("state"), null).as("state_is_null")]
})
.execute();
renvoie le résultat :
{state_is_null: true, total_population: 12130000}
{state_is_null: false, total_population: 13370000}
Comportements de l'agrégateur
Le comportement d'agrégation de chaque fonction compatible (par exemple, count, sum, avg) est
disponible sur la page dédiée aux
fonctions d'agrégation.
Comportements de la clé de groupe
Lors du regroupement de documents, Firestore utilise une sémantique d'égalité pour déterminer si les valeurs appartiennent au même groupe.
Cela signifie que les valeurs équivalentes, par exemple les valeurs numériques mathématiquement équivalentes, quel que soit le type d'origine (entier 32 bits, entier 64 bits, nombres à virgule flottante, decimal128, etc.), sont toutes regroupées.
Par exemple, dans une collection numerics avec différents documents contenant des foo
valeurs de type entier 32 bits 1, entier 64 bits 1L et nombre à virgule flottante 1.0
respectivement, elles seront toutes accumulées dans le même groupe. L'exécution d'un regroupement de comptage par foo renverra le résultat suivant :
{foo: 1.0, count: 3}
Dans de tels cas où différentes valeurs équivalentes sont présentes dans l'ensemble de données, la valeur de sortie du groupe peut être n'importe laquelle de ces valeurs équivalentes.
Dans cet exemple, foo peut être 1, 1L, ou 1.0.
Même si cela semble déterministe, vous ne devez pas essayer de vous fier au comportement d'une valeur spécifique sélectionnée.
Utilisation de la mémoire
La manière dont l'agrégation sera exécutée dépend des index disponibles. Lorsqu'aucun index approprié n'est choisi par l'optimiseur de requête, l'agrégat doit mettre en mémoire tampon tous les groupes.
Si le nombre de groupes est très élevé ou si chaque groupe est très volumineux (par exemple, en cas de regroupement par valeurs volumineuses), cette étape peut manquer de mémoire.
Dans ce cas, vous devez appliquer des filtres pour limiter l'ensemble de données à agréger, regrouper les données sur des champs plus petits/moins nombreux ou créer des index comme recommandé pour éviter une utilisation importante de la mémoire. La fonctionnalité "Expliquer la requête" fournit des informations sur le plan d'exécution réel de la requête et des données de profilage pour faciliter le débogage.