$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen
Oppijat ohjaavat koostamisen tulosteen uuteen tai olemassa olevaan kokoelmaan käyttämällä $out- ja $merge-operaattoreita ETL-prosesseihin ja materialisoituihin näkymiin.
$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen on ilmainen MongoDB Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu MongoDB Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.
Putken tulosten kirjoittaminen kokoelmiin
Oletusarvoisesti aggregointiputken tulokset palautetaan asiakkaalle kursorina. Joskus haluatte tallentaa tulokset pysyvästi MongoDB-kokoelmaan, jotta niitä voidaan käyttää myöhemmin materialisoituna näkymänä, raportointivälimuistina tai ETL-kohteena. MongoDB tarjoaa tähän kaksi vaihetta: $out korvaa kohdekokoelman atomisesti ja $merge lisää tai yhdistää tulokset olemassa olevaan kokoelmaan.
$out-vaihe
$out kirjoittaa kaikki putken tulosdokumentit uuteen tai olemassa olevaan kokoelmaan atomisena operaationa. Jos kohdekokoelma on olemassa, $out korvaa sen kokonaan uusilla tuloksilla — vanha kokoelma poistetaan ja uusi asetetaan sen tilalle atomisesti. Jos kokoelmaa ei ole, MongoDB luo sen. $out-vaiheen on oltava putken viimeinen vaihe, eikä se palauta asiakkaalle mitään.
// 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
]);$out-operaation atomisuus
$out tarjoaa atomisen korvaamisen: se kirjoittaa kaikki tulokset ensin väliaikaiseen kokoelmaan ja nimeää sitten väliaikaisen kokoelman kohdenimelle yhdellä atomisella operaatiolla. Tämän ansiosta kohdekokoelman lukijat näkevät aina joko vanhat täydelliset tiedot tai uudet täydelliset tiedot — eivät koskaan osittaista tulosta. Siksi $out soveltuu turvallisesti tuotantokäyttöön raportointikokoelman päivittäiseen päivitykseen.
// 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 eri tietokantaan
MongoDB 4.4:stä lähtien $out tukee objektimuotoista syntaksia, jonka avulla kokoelmaan voidaan kirjoittaa eri tietokannassa. Määritä objektimuodossa sekä db (tietokannan nimi) että coll (kokoelman nimi). Tämä on hyödyllistä, kun operatiiviset ja raportointitietokannat halutaan pitää erillään samassa klusterissa.
// 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$merge-vaihe
MongoDB 4.2:ssa esitelty $merge on joustavampi kuin $out: kohdekokoelman korvaamisen sijaan se upsertoi jokaisen tulosdokumentin kohteeseen. Määritätte yhdistämisavaimen eli kentän tai kentät, jotka yksilöivät olemassa olevat dokumentit. Kunkin tulosdokumentin kohdalla MongoDB ratkaisee, lisätäänkö se uutena, päivitetäänkö olemassa oleva dokumentti, korvataanko se, aiheutetaanko virhe vai säilytetäänkö nykyinen dokumentti.
// 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
}
}
]);$merge:n whenMatched-asetukset
whenMatched-asetus määrittää, mitä tapahtuu, kun putken tulosdokumentti vastaa kohdekokoelmassa olevaa dokumenttia. Vaihtoehdot ovat: 'replace' — korvaa olemassa olevan dokumentin; 'merge' — yhdistää kentät (tuloksessa puuttuvat olemassa olevat kentät säilytetään); 'keepExisting' — ei tee mitään vaan säilyttää olemassa olevan dokumentin; 'fail' — aiheuttaa virheen; tai mukautettu putki monimutkaista päivityslogiikkaa varten.
// 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$merge:n whenNotMatched-asetukset
whenNotMatched-asetus määrittää, mitä tapahtuu, kun putken tulosdokumentille ei löydy vastaavuutta kohdekokoelmasta. Vaihtoehdot ovat: 'insert' — lisää uuden dokumentin kohteeseen; 'discard' — ohita dokumentti (älä lisää sitä); tai 'fail' — aiheuta virhe. Yleisin yhdistelmä on whenMatched: 'replace', whenNotMatched: 'insert', joka toteuttaa täydellisen upsert-toiminnon.
// 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
}}Inkrementaaliset materialisoidut näkymät $merge:n avulla
Yksi $merge-operaation mahdollistamista tehokkaimmista käyttötavoista ovat inkrementaaliset materialisoidut näkymät: koko yhteenvedon uudelleenlaskemisen sijaan putki suoritetaan vain uudelle datalle (käyttämällä viimeaikaiseen aikaleimaan kohdistuvaa $match-ehtoa), ja inkrementaaliset tulokset yhdistetään yhteenvetokokoelmaan. Näin päivitys nopeutuu huomattavasti suurilla aineistoilla.
// 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 vai $merge: milloin kumpaakin käytetään
Käyttäkää $out-operaatiota, kun haluatte korvata koko tilannevedoksen: kohteen tulee aina sisältää putken koko tuore tulos — ei osittaisia päivityksiä eikä säilytettävää historiaa. Se sopii esimerkiksi yöaikaisiin eräraportteihin, jotka korvaavat edellisen päivän tiedot. Käyttäkää $merge-operaatiota, kun haluatte päivittää tietoja inkrementaalisesti, lisätä niitä tai upsertoida niitä olemassa olevaan kokoelmaan menettämättä tietoja, joita ei laskettu uudelleen tämän suorituksen aikana. Se sopii esimerkiksi tunnin välein suoritettavaan reaaliaikaiseen tai lähes reaaliaikaiseen aggregointiin.
// $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'
}}$out- ja $merge-kohteiden käyttöoikeudet ja indeksit
Kun $out luo kokoelman uudelleen, se poistaa kaikki kohteen indeksit (lukuun ottamatta _id-indeksiä). Kaikki toissijaiset indeksit on luotava uudelleen $out-suorituksen jälkeen. $merge säilyttää kohdekokoelman olemassa olevat indeksit. Tämä on yksi syy suosia $merge-operaatiota usein päivitettävissä kokoelmissa — indeksit eivät katoa jokaisen suorituksen yhteydessä.
// 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-putket $merge:n avulla
$merge mahdollistaa MongoDB-natiiviset ETL (Extract-Transform-Load) -putket: data poimitaan lähdekokoelmasta, muunnetaan aggregointivaiheiden avulla ja ladataan kohdekokoelmaan. Näin tavallisiin saman MongoDB-klusterin sisäisiin tiedonsiirtotehtäviin ei tarvita ulkoista ETL-työkalua.
// 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'
}}
]);Pikatarkistus
Testatkaa, miten hyvin ymmärrätte $out- ja $merge-putkivaiheet.
Oppitunnin kertaus
Tässä oppitunnissa opitte, että $out korvaa kohdekokoelman atomisesti mutta poistaa toissijaiset indeksit, $merge upsertoi dokumentteja määritettävillä whenMatched- ja whenNotMatched-toiminnoilla ja että inkrementaaliset materialisoidut näkymät $merge-operaation avulla mahdollistavat tehokkaat osittaiset päivitykset. Tämä päättää Advanced Aggregation Stages -kurssin — seuraavaksi tutustumme aggregoinnin akkumulaattoreihin perusteellisesti.
Opi JavaScript tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 30
- Oppitunnit
- 120
Usein kysytyt kysymykset
Onko oppitunti ”$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen” ilmainen?
Kyllä – oppitunnin ”$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko MongoDB Academy-kurssin, päivitä CoddyKit PROhon. MongoDB Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen”?
Oppijat ohjaavat koostamisen tulosteen uuteen tai olemassa olevaan kokoelmaan käyttämällä $out- ja $merge-operaattoreita ETL-prosesseihin ja materialisoituihin näkymiin. Harjoittelet MongoDB Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni MongoDB Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin MongoDB Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”$out ja $merge: Putkikäsittelyn tulosten kirjoittaminen”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä MongoDB Academy-oppitunnilla?
Kyllä. Jokainen MongoDB Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- $lookup: Kokoelmien yhdistäminen putkikäsittelyssä
- $unwind: Taulukkokenttien hajottaminen
- $addFields, $replaceRoot ja $mergeObjects
- $out ja $merge: Putkikäsittelyn tulosten kirjoittaminen