$out en $merge: pipeline-resultaten schrijven
U schrijft aggregatie-uitvoer naar een nieuwe of bestaande collectie met $out en $merge voor ETL en gematerialiseerde views.
$out en $merge: pipeline-resultaten schrijven is een gratis MongoDB Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject MongoDB Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus MongoDB Academy bevat in totaal 4 lessen.
Pijplijnresultaten naar collecties schrijven
Standaard worden resultaten van een aggregatiepijplijn als een cursor naar de client teruggestuurd. Soms wil je de resultaten opslaan in een MongoDB-collectie voor later gebruik als gematerialiseerde weergave, rapportagecache of ETL-doel. MongoDB biedt hiervoor twee fasen: $out, die een doelcollectie atomair vervangt, en $merge, die resultaten invoegt of samenvoegt met een bestaande collectie.
De fase $out
$out schrijft alle uitvoerdocumenten van de pijplijn naar een nieuwe of bestaande collectie in één atomaire bewerking. Als de doelcollectie bestaat, $out vervangt deze volledig door de nieuwe resultaten: de oude collectie wordt verwijderd en de nieuwe neemt deze atomair over. Als de collectie niet bestaat, maakt MongoDB deze aan. $out moet de laatste fase in de pijplijn zijn en retourneert niets naar de client.
// 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
]);Atomiciteitsgarantie van $out
$out biedt atomische vervanging: eerst schrijft het alle resultaten naar een tijdelijke collectie en daarna wordt de tijdelijke collectie in één atomaire bewerking hernoemd naar de doelnaam. Dit betekent dat lezers van de doelcollectie altijd óf de oude volledige gegevens óf de nieuwe volledige gegevens zien, nooit een gedeeltelijk resultaat. Daardoor is $out veilig voor productiegebruik als dagelijkse vernieuwing van een rapportagecollectie.
// 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
]);$out naar een andere database
Sinds MongoDB 4.4 ondersteunt $out een objectsyntaxis waarmee je naar een collectie in een andere database kunt schrijven. Geef in de objectvorm zowel db (databasenaam) als coll (collectienaam) op. Dit is handig om operationele databases en rapportagedatabases op hetzelfde cluster van elkaar te scheiden.
// 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_revenueDe fase $merge
$merge, geïntroduceerd in MongoDB 4.2, is flexibeler dan $out: in plaats van de doelcollectie te vervangen, voert het voor elk uitvoerdocument een upsert uit naar de doelcollectie. Je definieert de samenvoegsleutel (welk veld of welke velden bestaande documenten identificeren), waarna MongoDB voor elk uitvoerdocument bepaalt of het moet worden ingevoegd, een bestaand document moet bijwerken of vervangen, moet mislukken, of het bestaande document moet behouden.
// 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
}
}
]);Opties voor $merge whenMatched
De optie whenMatched bepaalt wat er gebeurt wanneer een uitvoerdocument van de pijplijn overeenkomt met een bestaand document in de doelcollectie. De opties zijn: 'replace' — het bestaande document overschrijven; 'merge' — velden samenvoegen (bestaande velden die niet in de uitvoer staan, blijven behouden); 'keepExisting' — niets doen en het bestaande document behouden; 'fail' — een fout veroorzaken; of een aangepaste pijplijn voor complexe updatelogica.
// 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 replacingOpties voor $merge whenNotMatched
De optie whenNotMatched bepaalt wat er gebeurt wanneer een uitvoerdocument van de pijplijn geen overeenkomst heeft in de doelcollectie. De opties zijn: 'insert' — het nieuwe document aan de doelcollectie toevoegen; 'discard' — het negeren (niet invoegen); of 'fail' — een fout veroorzaken. De meest voorkomende combinatie is whenMatched: 'replace', whenNotMatched: 'insert', waarmee een volledige upsert wordt uitgevoerd.
// 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
}}Incrementele gematerialiseerde weergaven met $merge
Een van de krachtigste patronen die $merge mogelijk maakt, zijn incrementele gematerialiseerde weergaven: in plaats van de volledige samenvatting telkens opnieuw te berekenen, voer je de pijplijn alleen uit op nieuwe gegevens (met een $match op een recente tijdstempel) en voeg je de incrementele resultaten samen met de samenvattingscollectie. Hierdoor verloopt het vernieuwen veel sneller voor grote gegevensverzamelingen.
// 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 versus $merge: wanneer gebruik je welke
Gebruik $out wanneer je een volledige snapshotvervanging wilt: de doelcollectie moet altijd het volledige, actuele resultaat van de pijplijn bevatten, zonder gedeeltelijke updates of bewaarde geschiedenis. Dit is geschikt voor nachtelijke batchrapporten die de gegevens van gisteren vervangen. Gebruik $merge wanneer je een bestaande collectie incrementeel wilt bijwerken, aanvullen of upserten zonder gegevens te verliezen die tijdens deze uitvoering niet opnieuw zijn berekend. Dit is geschikt voor realtime of bijna-realtime aggregatie die elk uur wordt uitgevoerd.
// $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'
}}Rechten en indexen op $out/$merge-doelen
Wanneer $out een collectie opnieuw maakt, verwijdert het alle indexen op het doel, behalve de _id-index. Je moet secundaire indexen na een uitvoering van $out opnieuw maken. $merge behoudt bestaande indexen op de doelcollectie. Dit is nog een reden om $merge te verkiezen voor collecties die vaak worden vernieuwd: je raakt je indexen niet bij elke uitvoering kwijt.
// 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 $mergeETL-pijplijnen met $merge
$merge maakt MongoDB-native ETL (Extract-Transform-Load)-pijplijnen mogelijk: haal gegevens uit een broncollectie, transformeer ze via aggregatiefasen en laad de resultaten in een doelcollectie. Hierdoor is voor veelvoorkomende taken voor gegevensverplaatsing binnen hetzelfde MongoDB-cluster geen externe ETL-tool nodig.
// 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'
}}
]);Korte controle
Toets je begrip van de fasen $out en $merge in een pijplijn.
Samenvatting van de les
In deze les heb je geleerd dat $out een doelcollectie atomair vervangt maar secundaire indexen verwijdert, dat $merge documenten upsert met instelbaar gedrag voor whenMatched en whenNotMatched, en dat incrementele gematerialiseerde weergaven met $merge efficiënte gedeeltelijke vernieuwingen mogelijk maken. Hiermee is de cursus Geavanceerde aggregatiefasen afgerond. Hierna onderzoeken we aggregatie-accumulatoren in detail.
Leer JavaScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 30
- Lessen
- 120
Veelgestelde vragen
Is de les “$out en $merge: pipeline-resultaten schrijven” gratis?
Ja — de volledige tekst van “$out en $merge: pipeline-resultaten schrijven” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus MongoDB Academy wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus MongoDB Academy bevat in totaal 4 lessen.
Wat leer ik in “$out en $merge: pipeline-resultaten schrijven”?
U schrijft aggregatie-uitvoer naar een nieuwe of bestaande collectie met $out en $merge voor ETL en gematerialiseerde views. Je oefent met MongoDB Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met MongoDB Academy te beginnen?
Ervaring vooraf is niet nodig. MongoDB Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “$out en $merge: pipeline-resultaten schrijven”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over MongoDB Academy?
Ja. Elke les over MongoDB Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- $lookup: collecties samenvoegen in de pipeline
- $unwind: arrayvelden uitvouwen
- $addFields, $replaceRoot en $mergeObjects
- $out en $merge: pipeline-resultaten schrijven