MongoDB Academy · Pelajaran

$out dan $merge: Menulis Hasil Saluran Paip

Pelajar akan menghalakan output agregasi ke dalam koleksi baharu atau sedia ada menggunakan $out dan $merge untuk ETL serta paparan terwujud.

Pelajaran 4 daripada 413 langkah

$out dan $merge: Menulis Hasil Saluran Paip ialah pelajaran MongoDB Academy percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Anda boleh membaca keseluruhan pelajaran di bawah secara percuma — kemudian berlatih secara praktikal dalam pelayar menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran MongoDB Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus MongoDB Academy merangkumi sejumlah 4 pelajaran.

Menulis Hasil Saluran Paip ke dalam Koleksi

Secara lalai, hasil saluran paip pengagregatan dikembalikan kepada klien sebagai kursor. Kadangkala anda mahu menyimpan hasil secara kekal ke dalam koleksi MongoDB untuk digunakan kemudian sebagai pandangan terwujud, cache pelaporan atau sasaran ETL. MongoDB menyediakan dua peringkat untuk tujuan ini: $out, yang menggantikan koleksi sasaran secara atomik, dan $merge, yang melakukan upsert atau menggabungkan hasil ke dalam koleksi sedia ada.

Peringkat $out

$out menulis semua dokumen output saluran paip ke dalam koleksi baharu atau sedia ada melalui operasi atomik. Jika koleksi sasaran wujud, $out menggantikannya sepenuhnya dengan hasil baharu—koleksi lama digugurkan dan koleksi baharu mengambil tempatnya secara atomik. Jika koleksi itu tidak wujud, MongoDB akan menciptanya. $out mesti menjadi peringkat terakhir dalam saluran paip dan tidak mengembalikan apa-apa kepada klien.

// 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
]);

Jaminan Keatomikan $out

$out menyediakan penggantian atomik: ia menulis semua hasil ke koleksi sementara terlebih dahulu, kemudian menamakan semula koleksi sementara itu kepada nama sasaran dalam satu operasi atomik. Ini bermakna pembaca koleksi sasaran sentiasa melihat sama ada data lama yang lengkap atau data baharu yang lengkap—tidak pernah hasil separa. Oleh itu, $out selamat digunakan dalam persekitaran produksi untuk menyegarkan koleksi pelaporan setiap hari.

// 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 ke Pangkalan Data Lain

Sejak MongoDB 4.4, $out menyokong sintaks objek yang membolehkan anda menulis ke koleksi dalam pangkalan data lain. Nyatakan kedua-dua db (nama pangkalan data) dan coll (nama koleksi) dalam bentuk objek. Ini berguna untuk mengasingkan pangkalan data operasi dan pelaporan dalam kelompok yang sama.

// 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

Peringkat $merge

Diperkenalkan dalam MongoDB 4.2, $merge lebih fleksibel daripada $out: bukannya menggantikan koleksi sasaran, ia melakukan upsert bagi setiap dokumen output ke dalam sasaran. Anda mentakrifkan kunci gabungan (medan yang mengenal pasti dokumen sedia ada), kemudian MongoDB menentukan sama ada setiap dokumen output perlu dimasukkan, dikemas kini, digantikan, menyebabkan kegagalan atau mengekalkan dokumen sedia ada.

// 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
    }
  }
]);

Pilihan $merge whenMatched

Pilihan whenMatched mengawal perkara yang berlaku apabila dokumen output saluran paip sepadan dengan dokumen sedia ada dalam koleksi sasaran. Pilihannya ialah: 'replace' — menulis ganti dokumen sedia ada; 'merge' — menggabungkan medan (medan sedia ada yang tiada dalam output dikekalkan); 'keepExisting' — tidak melakukan apa-apa dan mengekalkan dokumen sedia ada; 'fail' — menghasilkan ralat; atau saluran paip tersuai untuk logik kemas kini yang kompleks.

// 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

Pilihan $merge whenNotMatched

Pilihan whenNotMatched mengawal perkara yang berlaku apabila dokumen output saluran paip tidak mempunyai padanan dalam koleksi sasaran. Pilihannya ialah: 'insert' — menambah dokumen baharu ke sasaran; 'discard' — mengabaikannya (tidak memasukkannya); atau 'fail' — menghasilkan ralat. Gabungan yang paling biasa ialah whenMatched: 'replace', whenNotMatched: 'insert', yang melaksanakan upsert penuh.

// 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
}}

Paparan Terwujud Berperingkat Dengan $merge

Salah satu corak paling berkuasa yang didayakan oleh $merge ialah paparan terwujud berperingkat: bukannya mengira semula keseluruhan ringkasan setiap kali, anda menjalankan saluran paip hanya pada data baharu (menggunakan $match pada cap masa terkini) dan menggabungkan hasil berperingkat itu ke dalam koleksi ringkasan. Ini menjadikan penyegaran jauh lebih pantas bagi set data yang besar.

// 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 berbanding $merge: Bila Perlu Menggunakan Setiap Satu

Gunakan $out apabila anda mahukan penggantian gambaran penuh: sasaran hendaklah sentiasa menjadi hasil lengkap dan terkini daripada saluran paip—tiada kemas kini separa dan tiada sejarah yang dikekalkan. Sesuai untuk laporan kelompok malam yang menggantikan data semalam. Gunakan $merge apabila anda mahu mengemas kini secara berperingkat, menambah data atau melakukan upsert ke dalam koleksi sedia ada tanpa kehilangan data yang tidak dikira semula dalam larian ini. Sesuai untuk pengagregatan masa nyata atau hampir masa nyata yang dijalankan setiap jam.

// $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'
}}

Keizinan dan Indeks pada Sasaran $out/$merge

Apabila $out mencipta semula koleksi, ia menggugurkan semua indeks pada sasaran (kecuali indeks _id). Anda mesti mencipta semula sebarang indeks sekunder selepas larian $out. $merge mengekalkan indeks sedia ada pada koleksi sasaran. Ini ialah satu lagi sebab untuk memilih $merge bagi koleksi yang kerap disegarkan—indeks anda tidak hilang pada setiap larian.

// 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

Saluran Paip ETL Dengan $merge

$merge membolehkan saluran paip ETL asli MongoDB (Extract-Transform-Load): mengekstrak data daripada koleksi sumber, mengubahnya melalui peringkat pengagregatan dan memuatkan hasilnya ke dalam koleksi destinasi. Ini mengelakkan keperluan menggunakan alat ETL luaran untuk tugas pemindahan data biasa dalam kelompok MongoDB yang sama.

// 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'
  }}
]);

Semakan Pantas

Uji pemahaman anda tentang peringkat saluran paip $out dan $merge.

Rumusan Pelajaran

Dalam pelajaran ini, anda mempelajari bahawa: $out menggantikan koleksi sasaran secara atomik tetapi menggugurkan indeks sekunder, $merge melakukan upsert dokumen dengan tingkah laku whenMatched dan whenNotMatched yang boleh dikonfigurasikan, dan paparan terwujud berperingkat dengan $merge membolehkan penyegaran separa yang cekap. Kursus Peringkat Pengagregatan Lanjutan ini telah selesai—seterusnya kita akan meneroka pengumpul pengagregatan dengan lebih mendalam.

Percuma untuk bermula

Pelajari JavaScript dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
30
Pelajaran
120

Soalan Lazim

Adakah pelajaran “$out dan $merge: Menulis Hasil Saluran Paip” percuma?

Ya — teks penuh “$out dan $merge: Menulis Hasil Saluran Paip” boleh dibaca secara percuma di web ini. Untuk berlatih secara interaktif menggunakan penyunting kod terbina dalam dan tutor kecerdasan buatan 24/7, serta membuka kunci baki kursus MongoDB Academy, tingkat taraf kepada CoddyKit PRO. Kursus MongoDB Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “$out dan $merge: Menulis Hasil Saluran Paip”?

Pelajar akan menghalakan output agregasi ke dalam koleksi baharu atau sedia ada menggunakan $out dan $merge untuk ETL serta paparan terwujud. Anda berlatih MongoDB Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan MongoDB Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran MongoDB Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “$out dan $merge: Menulis Hasil Saluran Paip” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran MongoDB Academy ini?

Ya. Setiap pelajaran MongoDB Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. $lookup: Menggabungkan Koleksi dalam Saluran Paip
  2. $unwind: Menguraikan Medan Tatasusunan
  3. $addFields, $replaceRoot dan $mergeObjects
  4. $out dan $merge: Menulis Hasil Saluran Paip
← Kembali ke MongoDB Academy