MongoDB Academy · leksjon

$out og $merge: Skrive pipeline-resultater

Deltakerne vil skrive aggregeringsresultater til en ny eller eksisterende samling ved hjelp av $out og $merge for ETL og materialiserte visninger.

Leksjon 4 av 413 trinn

$out og $merge: Skrive pipeline-resultater er en gratis leksjon i MongoDB Academy på CoddyKit. Dette er leksjon 4 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i MongoDB Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i MongoDB Academy inneholder totalt 4 leksjoner.

Skrive pipeline-resultater til samlinger

Som standard returneres resultater fra aggregasjonspipelines til klienten som en cursor. Noen ganger vil De lagre resultatene i en MongoDB-samling for senere bruk som en materialisert visning, en rapporteringsbuffer eller et ETL-mål. MongoDB tilbyr to steg for dette: $out, som atomisk erstatter en målsamling, og $merge, som utfører upsert eller slår sammen resultater i en eksisterende samling.

Steget $out

$out skriver alle utdatadokumentene fra pipelinen til en ny eller eksisterende samling i én atomisk operasjon. Hvis målsamlingen finnes, $out erstatter den fullstendig med de nye resultatene – den gamle samlingen slettes, og den nye tar atomisk dens plass. Hvis den ikke finnes, oppretter MongoDB den. $out må være det siste steget i pipelinen og returnerer ingenting til klienten.

// Materialise monthly sales summary into its own collection
db.orders.aggregate([
  { $match: { status: 'completed' } },
  { $group: {
    _id: {
      year: { $year: '$createdAt' },
      month: { $month: '$createdAt' }
    },
    totalRevenue: { $sum: '$amount' },
    orderCount: { $sum: 1 }
  }},
  { $sort: { '_id.year': 1, '_id.month': 1 } },
  { $out: 'monthly_sales_summary' }  // last stage, writes to collection
]);

<code>$out</code>-garanti for atomicitet

$out utfører en atomisk erstatning: først skriver den alle resultatene til en midlertidig samling, og deretter gir den den midlertidige samlingen målsamlingens navn i én atomisk operasjon. Det betyr at lesere av målsamlingen alltid ser enten de gamle, komplette dataene eller de nye, komplette dataene – aldri et delvis resultat. Dette gjør $out trygt å bruke i produksjon for daglig oppdatering av en rapportsamling.

// Readers of 'monthly_sales_summary' always see complete data
// Even while $out is running, they see the previous full snapshot
// Only after $out completes does the new snapshot become visible

// Scheduled nightly refresh pattern:
// 1. Run at midnight: aggregate([...stages..., { $out: 'sales_report' }])
// 2. During the day: app reads from 'sales_report' (fast, pre-computed)
// 3. Next midnight: repeat

db.orders.aggregate([
  ...stages,
  { $out: 'sales_report' }  // atomic swap
]);

<code>$out</code> til en annen database

Siden MongoDB 4.4 støtter $out en objektsyntaks som lar Dem skrive til en samling i en annen database. Angi både db (databasenavn) og coll (samlingsnavn) i objektformen. Dette er nyttig for å skille drifts- og rapportdatabaser på den samme klyngen.

// Write to a collection in a different database
db.orders.aggregate([
  { $match: { status: 'completed' } },
  { $group: { _id: '$region', revenue: { $sum: '$amount' } } },
  {
    $out: {
      db: 'reporting',          // target database
      coll: 'regional_revenue'  // target collection
    }
  }
]);
// Result is in reporting.regional_revenue

Steget $merge

$merge, som ble introdusert i MongoDB 4.2, er mer fleksibelt enn $out: i stedet for å erstatte målsamlingen utfører det en upsert av hvert utdatadokument i målet. De definerer flettenøkkelen, altså hvilke felt som identifiserer eksisterende dokumenter, og for hvert utdatadokument avgjør MongoDB om det skal settes inn, oppdatere et eksisterende dokument, erstatte det, mislykkes eller beholde det eksisterende dokumentet.

// Upsert daily stats into a persistent stats collection
db.events.aggregate([
  { $group: {
    _id: {
      date: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } },
      eventType: '$type'
    },
    count: { $sum: 1 }
  }},
  {
    $merge: {
      into: 'daily_event_stats',
      on: ['_id'],              // match key
      whenMatched: 'replace',   // update matching docs
      whenNotMatched: 'insert'  // insert new docs
    }
  }
]);

Alternativer for $merge whenMatched

Alternativet whenMatched styrer hva som skjer når et utdatadokument fra pipelinen samsvarer med et eksisterende dokument i målsamlingen. Alternativene er: 'replace' – overskriv det eksisterende dokumentet; 'merge' – flett felt (eksisterende felt som ikke finnes i resultatet, beholdes); 'keepExisting' – ikke gjør noe, og behold det eksisterende dokumentet; 'fail' – utløse en feil; eller en egendefinert pipeline for kompleks oppdateringslogikk.

// whenMatched: 'merge' - only update changed fields, keep others
db.orders.aggregate([
  { $project: { userId: 1, orderCount: { $literal: 1 } } },
  { $merge: {
    into: 'user_order_counts',
    on: 'userId',
    whenMatched: [{ $set: { orderCount: { $add: ['$orderCount', '$$new.orderCount'] } } }],
    whenNotMatched: 'insert'
  }}
]);
// Custom pipeline in whenMatched adds to existing count instead of replacing

Alternativer for $merge whenNotMatched

Alternativet whenNotMatched styrer hva som skjer når et utdatadokument fra pipelinen ikke har noe samsvar i målsamlingen. Alternativene er: 'insert' – legg det nye dokumentet til i målet; 'discard' – ignorer det (ikke sett det inn); eller 'fail' – utløse en feil. Den vanligste kombinasjonen er whenMatched: 'replace', whenNotMatched: 'insert', som implementerer en fullstendig upsert.

// Full upsert: replace existing, insert new
{ $merge: {
  into: 'product_stats',
  on: '_id',
  whenMatched: 'replace',
  whenNotMatched: 'insert'
}}

// Update only existing, silently skip new
{ $merge: {
  into: 'product_stats',
  on: '_id',
  whenMatched: 'replace',
  whenNotMatched: 'discard'  // only update existing products
}}

Inkrementelle materialiserte visninger med $merge

Et av de mest kraftfulle mønstrene som $merge muliggjør, er inkrementelle materialiserte visninger: i stedet for å beregne hele sammendraget på nytt hver gang, kjører De pipelinen bare på nye data (ved å bruke en $match på et nylig tidsstempel) og fletter de inkrementelle resultatene inn i sammendragsamlingen. Dette gjør oppdateringen mye raskere for store datasett.

// Incremental update: only process last hour of orders
const oneHourAgo = new Date(Date.now() - 3600000);

db.orders.aggregate([
  { $match: { createdAt: { $gte: oneHourAgo } } },  // only NEW data
  { $group: {
    _id: '$productId',
    recentRevenue: { $sum: '$amount' },
    recentOrders: { $sum: 1 }
  }},
  { $merge: {
    into: 'product_revenue',
    on: '_id',
    whenMatched: [
      { $set: {
        totalRevenue: { $add: ['$totalRevenue', '$$new.recentRevenue'] },
        totalOrders: { $add: ['$totalOrders', '$$new.recentOrders'] }
      }}
    ],
    whenNotMatched: 'insert'
  }}
]);

$out kontra $merge: Når skal de brukes

Bruk $out når De ønsker å erstatte et fullstendig øyeblikksbilde: målet skal alltid være det komplette, oppdaterte resultatet fra pipelinen – ingen delvise oppdateringer og ingen beholdt historikk. Dette passer godt for nattlige batchrapporter som erstatter gårsdagens data. Bruk $merge når De ønsker å oppdatere inkrementelt, legge til data eller utføre upsert i en eksisterende samling uten å miste data som ikke ble beregnet på nytt i denne kjøringen. Dette passer godt for aggregering i sanntid eller nær sanntid, for eksempel en kjøring hver time.

// $out: nightly full replace
// Run at midnight: compute full summary, atomically replace target
{ $out: 'monthly_report' }

// $merge: hourly incremental update
// Run every hour: compute last hour's delta, merge into running total
{ $merge: {
  into: 'running_totals',
  on: '_id',
  whenMatched: 'merge',
  whenNotMatched: 'insert'
}}

Tillatelser og indekser på mål for $out/$merge

Når $out oppretter en samling på nytt, sletter den alle indekser på målet, bortsett fra _id-indeksen. De må opprette eventuelle sekundærindekser på nytt etter en $out-kjøring. $merge bevarer eksisterende indekser på målsamlingen. Dette er enda en grunn til å foretrekke $merge for samlinger som oppdateres ofte – De mister ikke indeksene ved hver kjøring.

// After $out, recreate indexes on the refreshed collection
db.orders.aggregate([...stages, { $out: 'order_summary' }]);
// Now recreate needed indexes:
db.order_summary.createIndex({ userId: 1 });
db.order_summary.createIndex({ createdAt: -1 });

// $merge preserves existing indexes automatically
// No index recreation needed after $merge

ETL-pipeliner med $merge

$merge muliggjør MongoDB-basert ETL (Extract-Transform-Load): hent ut data fra en kildesamling, transformer dem gjennom aggregeringssteg, og last resultatene inn i en målsamling. Dette eliminerer behovet for et eksternt ETL-verktøy ved vanlige dataflyttingsoppgaver innenfor den samme MongoDB-klyngen.

// ETL: clean and transform raw events into a processed_events collection
db.raw_events.aggregate([
  // Extract: filter valid events
  { $match: { eventType: { $in: ['click', 'view', 'purchase'] }, userId: { $exists: true } } },
  // Transform: reshape and enrich
  { $addFields: {
    processedAt: '$$NOW',
    eventDate: { $dateToString: { format: '%Y-%m-%d', date: '$timestamp' } }
  }},
  { $project: { _id: 0, eventType: 1, userId: 1, eventDate: 1, processedAt: 1 } },
  // Load: upsert into destination
  { $merge: {
    into: 'processed_events',
    on: ['userId', 'eventDate', 'eventType'],
    whenMatched: 'keepExisting',  // don't reprocess
    whenNotMatched: 'insert'
  }}
]);

Hurtigsjekk

Test forståelsen Deres av pipeline-stegene $out og $merge.

Oppsummering av leksjonen

I denne leksjonen har De lært at $out erstatter en målsamling atomisk, men sletter sekundærindekser, at $merge utfører upsert av dokumenter med konfigurerbar oppførsel for whenMatched og whenNotMatched, og at inkrementelle materialiserte visninger med $merge muliggjør effektive delvise oppdateringer. Dette avslutter kurset Advanced Aggregation Stages – i neste del utforsker vi aggregeringsakkumulatorer i detalj.

Gratis å komme i gang

Lær deg JavaScript med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
30
Leksjoner
120

Ofte stilte spørsmål

Er leksjonen «$out og $merge: Skrive pipeline-resultater» gratis?

Ja – hele teksten i «$out og $merge: Skrive pipeline-resultater» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av MongoDB Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i MongoDB Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «$out og $merge: Skrive pipeline-resultater»?

Deltakerne vil skrive aggregeringsresultater til en ny eller eksisterende samling ved hjelp av $out og $merge for ETL og materialiserte visninger. Du øver på MongoDB Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med MongoDB Academy?

Ingen tidligere erfaring er nødvendig. MongoDB Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 4 av 4.

Hvor lang tid tar leksjonen «$out og $merge: Skrive pipeline-resultater»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne MongoDB Academy-leksjonen?

Ja. Alle MongoDB Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. $lookup: Slå sammen samlinger i pipelinen
  2. $unwind: Dekonstruere matrisefelt
  3. $addFields, $replaceRoot og $mergeObjects
  4. $out og $merge: Skrive pipeline-resultater
← Tilbake til MongoDB Academy