Agrégations par fenêtre sur des séries temporelles
Les apprenants utiliseront $setWindowFields avec des bornes de fenêtre fondées sur le temps pour calculer des moyennes glissantes et des sommes cumulées sur des relevés de capteurs.
Agrégations par fenêtre sur des séries temporelles est une leçon MongoDB Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage MongoDB Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours MongoDB Academy comprend 4 leçons au total.
Que sont les fonctions de fenêtre ?
Une fonction de fenêtre calcule une valeur pour chaque document d’un ensemble de résultats en examinant une plage environnante (la « fenêtre ») de documents, sans les regrouper comme le fait $group. Chaque document d’entrée produit exactement un document de sortie, mais la valeur calculée reflète l’agrégation effectuée sur la fenêtre. MongoDB a ajouté les fonctions de fenêtre via l’étape $setWindowFields dans la version 5.0.
L’étape $setWindowFields
$setWindowFields est l’étape d’agrégation qui active les fonctions de fenêtre dans MongoDB. Elle accepte une expression partitionBy (semblable à PARTITION BY en SQL), un objet output définissant de nouveaux champs et leurs opérateurs de fenêtre, ainsi qu’un document sortBy qui établit l’ordre au sein de chaque partition. Cette combinaison est idéale pour les séries temporelles : partitionner par capteur, trier par horodatage, puis calculer des totaux cumulés ou des moyennes mobiles.
db.sensorReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$sensorId', // one window per sensor
sortBy: { timestamp: 1 }, // ordered by time ascending
output: {
runningTotal: {
$sum: '$temperature',
window: { documents: ['unbounded', 'current'] }
}
}
}
}
])Limites de fenêtre fondées sur les documents
Les limites d’une fenêtre peuvent être spécifiées en fonction de la position des documents par rapport au document actuel. Les mots-clés spéciaux 'unbounded' (depuis le premier document de la partition) et 'current' (le document actuel) définissent des limites courantes. Vous pouvez également utiliser des nombres entiers : [-3, 0] signifie les 3 documents précédents et le document actuel, ce qui convient parfaitement à une moyenne mobile sur 4 points.
// 5-point rolling average (2 before, current, 2 after)
db.sensorReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
rollingAvgTemp: {
$avg: '$temperature',
window: { documents: [-2, 2] }
}
}
}
}
])Fenêtres temporelles fondées sur une plage
Pour les données de séries temporelles, les fenêtres fondées sur une plage sont plus naturelles que celles fondées sur les documents, car les données peuvent arriver à des intervalles irréguliers. Les fenêtres fondées sur une plage utilisent une unité (les millisecondes par défaut) et une quantité relative à la valeur de tri du document actuel. Par exemple, une fenêtre glissante d’une heure vers le passé serait { range: [-3600000, 0], unit: 'millisecond' }. Les unités temporelles dédiées telles que 'hour', 'minute' et 'second' sont également prises en charge.
// 1-hour trailing moving average by time range
db.sensorReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
movingAvgTemp: {
$avg: '$temperature',
window: {
range: [-1, 0],
unit: 'hour'
}
}
}
}
}
])Totaux cumulés avec $sum
Un total cumulé (ou somme cumulative) se calcule en définissant la fenêtre de 'unbounded' à 'current'. Le champ de sortie de chaque document contient la somme de toutes les valeurs depuis le premier document de la partition jusqu'au document courant inclus. Cela est utile pour calculer la consommation d'énergie cumulée, le nombre total de transactions ou le volume d'octets transférés au fil du temps.
// Cumulative energy consumption per device
db.energyReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$deviceId',
sortBy: { timestamp: 1 },
output: {
cumulativeKwh: {
$sum: '$kwh',
window: { documents: ['unbounded', 'current'] }
}
}
}
},
{ $project: { _id: 0, timestamp: 1, deviceId: 1, kwh: 1, cumulativeKwh: 1 } }
])Classement avec $rank et $denseRank
$rank et $denseRank sont des opérateurs de fenêtre qui attribuent des positions aux documents de leur partition, selon l'ordre défini par l'expression sortBy. $rank laisse des écarts dans la numérotation en cas d'égalité (1, 2, 2, 4…), contrairement à $denseRank (1, 2, 2, 3…). Ils sont utiles pour classer les capteurs selon leur dernière mesure ou identifier les N appareils les plus performants.
// Rank sensors by their average temperature (after grouping)
db.sensorStats.aggregate([
{
$setWindowFields: {
partitionBy: null, // no partition — global rank
sortBy: { avgTemp: -1 }, // highest temp ranked first
output: {
rank: { $rank: {} }
}
}
}
])Numéros de ligne avec $documentNumber
$documentNumber attribue à chaque document de sa partition un entier séquentiel commençant à 1, selon l'ordre défini par sortBy. Contrairement à $rank, il ne produit jamais d'égalité : chaque document reçoit un numéro unique. Cela est pratique pour la pagination, la numérotation par lots des exportations ou l'étiquetage d'événements séquentiels dans un flux de données de capteurs.
db.sensorReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
readingNumber: { $documentNumber: {} }
}
}
},
{ $match: { sensorId: 'sensor-42' } }
])Décalage des valeurs : opérateur $shift
L'opérateur $shift permet d'accéder à la valeur d'un champ d'un document situé à une position relative. { $shift: { output: '$temperature', by: -1 } } renvoie la température du document précédent dans la partition. C'est idéal pour calculer des écarts — la différence entre la mesure courante et celle qui la précède — et ainsi mettre en évidence le taux de variation des données des capteurs.
// Compute temperature delta vs previous reading
db.sensorReadings.aggregate([
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
prevTemp: {
$shift: { output: '$temperature', by: -1, default: null }
}
}
}
},
{
$addFields: {
tempDelta: { $subtract: ['$temperature', '$prevTemp'] }
}
}
])Combiner $setWindowFields avec $match
Placez toujours une étape $match avant $setWindowFields afin de réduire l'ensemble de travail. Les calculs sur les fenêtres sont effectués en mémoire ; fournir moins de documents à l'étape réduit donc considérablement l'utilisation de la RAM. Après l'étape de fenêtre, vous pouvez ajouter un autre $match pour filtrer le résultat enrichi, par exemple en ne conservant que les documents dont la moyenne glissante dépasse un seuil.
// Flag anomalies where temp spikes above rolling average
db.sensorReadings.aggregate([
{
$match: {
sensorId: 'sensor-42',
timestamp: { $gte: new Date('2024-06-01T00:00:00Z') }
}
},
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
rollingAvg: {
$avg: '$temperature',
window: { documents: [-9, 0] }
}
}
}
},
{
$match: {
$expr: { $gt: ['$temperature', { $multiply: ['$rollingAvg', 1.2] }] }
}
}
])Performances : la taille des partitions est importante
$setWindowFields doit conserver chaque partition en mémoire pour calculer les valeurs de fenêtre. Pour les données de séries temporelles, cela correspond aux données d'un capteur pour la période demandée. Si vos partitions sont extrêmement volumineuses (des millions de mesures), envisagez un préfiltrage avec $match ou utilisez allowDiskUse: true lors de l'agrégation afin de décharger les partitions sur le disque. Vous pouvez également effectuer une préagrégation en résumés horaires avant d'appliquer les fonctions de fenêtre.
// Allow disk use for very large partitions
db.sensorReadings.aggregate(
[
{ $match: { timestamp: { $gte: new Date('2024-01-01T00:00:00Z') } } },
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
rolling7d: {
$avg: '$temperature',
window: { range: [-7, 0], unit: 'day' }
}
}
}
}
],
{ allowDiskUse: true }
)Exemple pratique : détection d'anomalies
Une chaîne complète de détection d'anomalies combine $match pour filtrer une plage, $setWindowFields avec une fenêtre rétrospective pour calculer la moyenne glissante et l'écart type, puis un $match final avec $expr pour faire ressortir les mesures qui s'écartent de plus de 2 écarts types de la moyenne locale. Ce modèle constitue la base des systèmes de surveillance IoT en temps réel.
db.sensorReadings.aggregate([
{ $match: { timestamp: { $gte: new Date('2024-06-01T00:00:00Z') } } },
{
$setWindowFields: {
partitionBy: '$sensorId',
sortBy: { timestamp: 1 },
output: {
rollingAvg: { $avg: '$temperature', window: { documents: [-19, 0] } },
rollingStdDev: { $stdDevSamp: '$temperature', window: { documents: [-19, 0] } }
}
}
},
{
$match: {
$expr: {
$gt: [
{ $abs: { $subtract: ['$temperature', '$rollingAvg'] } },
{ $multiply: ['$rollingStdDev', 2] }
]
}
}
}
])Vérification rapide
Testez votre compréhension des concepts de MongoDB et des bases de données NoSQL présentés dans cette leçon.
Récapitulatif de la leçon
Dans cette leçon, vous avez appris que $setWindowFields enrichit chaque document avec des valeurs calculées sur une fenêtre environnante sans réduire le résultat, que les limites de documents et de plages permettent de contrôler précisément les fenêtres rétrospectives, prospectives ou couvrant une période, et que les opérateurs tels que $avg, $sum, $shift et $rank couvrent les moyennes mobiles, les totaux cumulés, le calcul des écarts et le classement. Nous allons maintenant découvrir l'expiration automatique des données avec expireAfterSeconds.
Apprends JavaScript avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 30
- Leçons
- 120
Questions Fréquemment Posées
La leçon « Agrégations par fenêtre sur des séries temporelles » est-elle gratuite ?
Oui — le texte complet de « Agrégations par fenêtre sur des séries temporelles » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours MongoDB Academy, passe à CoddyKit PRO. Le cours MongoDB Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Agrégations par fenêtre sur des séries temporelles » ?
Les apprenants utiliseront $setWindowFields avec des bornes de fenêtre fondées sur le temps pour calculer des moyennes glissantes et des sommes cumulées sur des relevés de capteurs. Tu pratiques MongoDB Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer MongoDB Academy ?
Aucune expérience préalable n'est requise. MongoDB Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Agrégations par fenêtre sur des séries temporelles » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon MongoDB Academy ?
Oui. Chaque leçon MongoDB Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Créer une collection de séries temporelles
- Insérer et interroger des données de séries temporelles
- Agrégations par fenêtre sur des séries temporelles
- Expiration automatique des données avec expireAfterSeconds