<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Document on Tarragon</title><link>https://tarrragon.github.io/blog/tags/document/</link><description>Recent content in Document on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Tue, 16 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/document/index.xml" rel="self" type="application/rss+xml"/><item><title>MongoDB</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/mongodb/</link><pubDate>Wed, 13 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/mongodb/</guid><description>&lt;p>MongoDB 是 document database 的事實標準。schema flexibility、aggregation pipeline、跨雲 managed（Atlas）讓它成為許多 startup 的 default 選擇。Microsoft 365、Disney+ 早期、Uber 等大規模平台都從 MongoDB 起家，後來依 workload 壓力把部分路徑遷移到 KV / 雲商專屬服務（Cosmos DB、DynamoDB）。&lt;/p>
&lt;h2 id="教學路線document-shape-與-schema-governance">教學路線：Document shape 與 schema governance&lt;/h2>
&lt;p>MongoDB 服務頁的教學目標是把 document model、schema flexibility、index、aggregation pipeline 與 sharding 放回資料形狀治理。讀者讀完後要能判斷資料是否適合 aggregate root，並知道 schema governance 如何影響長期維護成本。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>學習段&lt;/th>
 &lt;th>核心問題&lt;/th>
 &lt;th>對應段落&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Document shape&lt;/td>
 &lt;td>哪些資料適合 aggregate root 與 nested document&lt;/td>
 &lt;td>定位、適用場景&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Schema governance&lt;/td>
 &lt;td>schema flexibility 如何搭配 validation、版本與 migration&lt;/td>
 &lt;td>容量規劃要點、預計實作話題&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Query / index&lt;/td>
 &lt;td>index、aggregation pipeline、ad-hoc query 如何影響成本&lt;/td>
 &lt;td>容量特性、常見陷阱&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Sharding&lt;/td>
 &lt;td>shard key、chunk、balancer 如何把資料形狀變容量問題&lt;/td>
 &lt;td>容量規劃要點、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/database-sharding/" data-link-title="Database Sharding" data-link-desc="說明資料庫如何依 shard key 分散資料、路由請求與承擔跨 shard 查詢成本">Database Sharding&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>替代路由&lt;/td>
 &lt;td>何時轉 PostgreSQL、DynamoDB、Cosmos DB 或 search&lt;/td>
 &lt;td>不適用場景、跟其他 vendor 的取捨&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="定位json-document--跨雲彈性">定位：JSON document + 跨雲彈性&lt;/h2>
&lt;p>MongoDB 是以 document model 為主體的 DB。PostgreSQL JSONB 適合「SQL 為主、少量半結構化欄位」；MongoDB 則把 BSON document、aggregation pipeline、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/database-sharding/" data-link-title="Database Sharding" data-link-desc="說明資料庫如何依 shard key 分散資料、路由請求與承擔跨 shard 查詢成本">database sharding&lt;/a> 與 schema governance 放在核心設計裡。近年版本加入 time series、change streams、queryable encryption、CSFLE 等能力。&lt;/p>
&lt;p>選 MongoDB 的核心訴求：document model 是主要 use case、需要跨雲 managed（Atlas）、想避免 vendor lock-in（也可自管）。&lt;/p>
&lt;h2 id="容量特性">容量特性&lt;/h2>
&lt;p>&lt;strong>單一 instance 吞吐&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>一般 m5.4xlarge：5K-15K WPS（依 doc size、index）&lt;/li>
&lt;li>高階 instance + tuning：30K-50K WPS&lt;/li>
&lt;li>超過此級別 → sharding&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Sharding&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>MongoDB 原生支援 sharded cluster&lt;/li>
&lt;li>mongos router + config servers + shard&lt;/li>
&lt;li>MongoDB sharding 要主動設計 shard key，並和 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/hot-partition/" data-link-title="Hot Partition" data-link-desc="說明分散式 KV / OLTP 中、單一 partition 流量遠超其他的容量問題">Hot Partition&lt;/a> 風險一起看&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Replication&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>Replica set（primary + secondary、async）&lt;/li>
&lt;li>跨 region 通常 async&lt;/li>
&lt;li>自動 failover &amp;lt; 30 秒（mongod 內建）&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Storage&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>單一 collection 沒有官方上限、但 shard key resharding 過去版本是大手術（4.4+ 支援 reshardCollection）&lt;/li>
&lt;/ul>
&lt;h2 id="適用場景">適用場景&lt;/h2>
&lt;p>&lt;strong>1. Document model 主要 workload&lt;/strong>：&lt;/p></description><content:encoded><![CDATA[<p>MongoDB 是 document database 的事實標準。schema flexibility、aggregation pipeline、跨雲 managed（Atlas）讓它成為許多 startup 的 default 選擇。Microsoft 365、Disney+ 早期、Uber 等大規模平台都從 MongoDB 起家，後來依 workload 壓力把部分路徑遷移到 KV / 雲商專屬服務（Cosmos DB、DynamoDB）。</p>
<h2 id="教學路線document-shape-與-schema-governance">教學路線：Document shape 與 schema governance</h2>
<p>MongoDB 服務頁的教學目標是把 document model、schema flexibility、index、aggregation pipeline 與 sharding 放回資料形狀治理。讀者讀完後要能判斷資料是否適合 aggregate root，並知道 schema governance 如何影響長期維護成本。</p>
<table>
  <thead>
      <tr>
          <th>學習段</th>
          <th>核心問題</th>
          <th>對應段落</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Document shape</td>
          <td>哪些資料適合 aggregate root 與 nested document</td>
          <td>定位、適用場景</td>
      </tr>
      <tr>
          <td>Schema governance</td>
          <td>schema flexibility 如何搭配 validation、版本與 migration</td>
          <td>容量規劃要點、預計實作話題</td>
      </tr>
      <tr>
          <td>Query / index</td>
          <td>index、aggregation pipeline、ad-hoc query 如何影響成本</td>
          <td>容量特性、常見陷阱</td>
      </tr>
      <tr>
          <td>Sharding</td>
          <td>shard key、chunk、balancer 如何把資料形狀變容量問題</td>
          <td>容量規劃要點、<a href="/blog/backend/knowledge-cards/database-sharding/" data-link-title="Database Sharding" data-link-desc="說明資料庫如何依 shard key 分散資料、路由請求與承擔跨 shard 查詢成本">Database Sharding</a></td>
      </tr>
      <tr>
          <td>替代路由</td>
          <td>何時轉 PostgreSQL、DynamoDB、Cosmos DB 或 search</td>
          <td>不適用場景、跟其他 vendor 的取捨</td>
      </tr>
  </tbody>
</table>
<h2 id="定位json-document--跨雲彈性">定位：JSON document + 跨雲彈性</h2>
<p>MongoDB 是以 document model 為主體的 DB。PostgreSQL JSONB 適合「SQL 為主、少量半結構化欄位」；MongoDB 則把 BSON document、aggregation pipeline、<a href="/blog/backend/knowledge-cards/database-sharding/" data-link-title="Database Sharding" data-link-desc="說明資料庫如何依 shard key 分散資料、路由請求與承擔跨 shard 查詢成本">database sharding</a> 與 schema governance 放在核心設計裡。近年版本加入 time series、change streams、queryable encryption、CSFLE 等能力。</p>
<p>選 MongoDB 的核心訴求：document model 是主要 use case、需要跨雲 managed（Atlas）、想避免 vendor lock-in（也可自管）。</p>
<h2 id="容量特性">容量特性</h2>
<p><strong>單一 instance 吞吐</strong>：</p>
<ul>
<li>一般 m5.4xlarge：5K-15K WPS（依 doc size、index）</li>
<li>高階 instance + tuning：30K-50K WPS</li>
<li>超過此級別 → sharding</li>
</ul>
<p><strong>Sharding</strong>：</p>
<ul>
<li>MongoDB 原生支援 sharded cluster</li>
<li>mongos router + config servers + shard</li>
<li>MongoDB sharding 要主動設計 shard key，並和 <a href="/blog/backend/knowledge-cards/hot-partition/" data-link-title="Hot Partition" data-link-desc="說明分散式 KV / OLTP 中、單一 partition 流量遠超其他的容量問題">Hot Partition</a> 風險一起看</li>
</ul>
<p><strong>Replication</strong>：</p>
<ul>
<li>Replica set（primary + secondary、async）</li>
<li>跨 region 通常 async</li>
<li>自動 failover &lt; 30 秒（mongod 內建）</li>
</ul>
<p><strong>Storage</strong>：</p>
<ul>
<li>單一 collection 沒有官方上限、但 shard key resharding 過去版本是大手術（4.4+ 支援 reshardCollection）</li>
</ul>
<h2 id="適用場景">適用場景</h2>
<p><strong>1. Document model 主要 workload</strong>：</p>
<ul>
<li>schema 變化頻繁的早期產品</li>
<li>nested document 自然表達領域模型（訂單含多個 item、用戶含多個 preference）</li>
<li>對應案例：<a href="/blog/backend/09-performance-capacity/cases/microsoft-365-cosmos-db-analytics/" data-link-title="9.C30 Microsoft 365：從 MongoDB 遷移到 Cosmos DB 的分析平台" data-link-desc="Microsoft 365 把使用分析平台從 MongoDB 遷移到 Cosmos DB、planet-scale 全球分散式分析">9.C30 Microsoft 365</a> — 從 MongoDB 遷移到 Cosmos DB MongoDB API、保留 document model</li>
</ul>
<p><strong>2. Aggregation pipeline 重 workload</strong>：</p>
<ul>
<li>複雜的 $group / $match / $project chain</li>
<li>報表、analytics、ETL prep</li>
<li>比 RDBMS 寫複雜 query 更直觀（對某些 team）</li>
</ul>
<p><strong>3. 跨雲 managed（Atlas）</strong>：</p>
<ul>
<li>MongoDB Atlas 跨 AWS / GCP / Azure</li>
<li>跟 DynamoDB（AWS only）、Cosmos DB（Azure only）、Spanner（GCP only）相反</li>
<li>適合多雲策略、避免單一 vendor lock-in</li>
</ul>
<p><strong>4. Time series workload（6.0+）</strong>：</p>
<ul>
<li>time series collection 專屬優化</li>
<li>不過 InfluxDB / TimescaleDB 仍是更專業選擇</li>
</ul>
<p><strong>5. 已有 MongoDB 生態 + 想轉移操作責任</strong>：</p>
<ul>
<li>Atlas 提供 backup、failover、monitoring、auto-scale</li>
<li>想把 MongoDB DBA / SRE 操作責任交給 Atlas</li>
</ul>
<h2 id="不適用場景">不適用場景</h2>
<p><strong>1. 強 ACID multi-document transaction</strong>：</p>
<ul>
<li>MongoDB Transaction 支援多 document、但跨 shard 有性能影響</li>
<li>高頻金融交易仍建議 SQL 系統</li>
<li>替代：PostgreSQL、Aurora、Spanner</li>
</ul>
<p><strong>2. 複雜 JOIN</strong>：</p>
<ul>
<li>MongoDB <code>$lookup</code> 適合少量相鄰資料，JOIN-heavy workload 應回 SQL 系統</li>
<li>schema design 階段要把常用讀取路徑 denormalize 成 document shape</li>
<li>替代：SQL 系統做 JOIN-heavy workload</li>
</ul>
<p><strong>3. 純 KV + sub-ms latency</strong>：</p>
<ul>
<li>MongoDB document model 比 KV 多一層 BSON parsing</li>
<li>替代：Redis、DynamoDB、Bigtable</li>
</ul>
<p><strong>4. 大規模 OLAP</strong>：</p>
<ul>
<li>aggregation 對中等資料量還行、TB 級不適合</li>
<li>替代：ClickHouse、BigQuery、Spark on Delta Lake</li>
</ul>
<p><strong>5. 嚴格資料模型 + schema enforcement</strong>：</p>
<ul>
<li>MongoDB schema flexibility 可能導致 production data inconsistency</li>
<li>替代：SQL DB（schema 強制）+ JSONB column 處理半結構化</li>
</ul>
<h2 id="跟其他-vendor-的取捨">跟其他 vendor 的取捨</h2>
<p><strong>vs Cosmos DB MongoDB API</strong>：</p>
<ul>
<li>MongoDB Atlas：跨雲、原生 MongoDB 行為</li>
<li>Cosmos DB MongoDB API：Azure-only、global distribution + 5 <a href="/blog/backend/knowledge-cards/consistency-level/" data-link-title="Consistency Level" data-link-desc="資料系統對讀寫一致性語意的可選擇層級">consistency level</a>s</li>
<li>選 MongoDB Atlas：跨雲、需要原生 MongoDB features</li>
<li>選 Cosmos DB：Azure 生態、需要更好 global distribution</li>
<li>對應案例：<a href="/blog/backend/09-performance-capacity/cases/microsoft-365-cosmos-db-analytics/" data-link-title="9.C30 Microsoft 365：從 MongoDB 遷移到 Cosmos DB 的分析平台" data-link-desc="Microsoft 365 把使用分析平台從 MongoDB 遷移到 Cosmos DB、planet-scale 全球分散式分析">9.C30 Microsoft 365</a> — 從 MongoDB 遷到 Cosmos DB MongoDB API，主要保留 document model</li>
</ul>
<p><strong>vs DynamoDB</strong>：</p>
<ul>
<li>MongoDB：document model、aggregation 強、跨雲</li>
<li>DynamoDB：KV / single-table design、AWS 整合、5 個 9 SLA</li>
<li>選 MongoDB：document 為主、跨雲</li>
<li>選 DynamoDB：KV 為主、AWS 生態</li>
<li>詳見 <a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB vendor page</a> 對比段</li>
</ul>
<p><strong>vs PostgreSQL JSONB</strong>：</p>
<ul>
<li>MongoDB：document 為主、schema-less</li>
<li>PostgreSQL：SQL 為主、JSONB 補充</li>
<li>選 MongoDB：document 占主要 schema</li>
<li>選 PostgreSQL JSONB：主要結構化、少量半結構化欄位</li>
</ul>
<p><strong>vs Couchbase / Couchdb / Firestore</strong>：</p>
<ul>
<li>Couchbase：MongoDB 替代、有 N1QL（SQL-like）</li>
<li>CouchDB：偏小規模、master-master replication</li>
<li>Firestore：GCP-only、realtime updates</li>
<li>MongoDB 在這群裡是生態最廣的</li>
</ul>
<p><strong>vs Elasticsearch 作為 search 替代</strong>：</p>
<ul>
<li>兩者分屬不同類別：MongoDB 是 OLTP / document、Elasticsearch 是 search + analytics</li>
<li>通常搭配用：MongoDB 主、Elasticsearch 處理 full-text search</li>
</ul>
<h2 id="容量規劃要點">容量規劃要點</h2>
<p><strong>1. Shard key 設計是命脈</strong>：</p>
<ul>
<li>跟 DynamoDB partition key 同樣關鍵</li>
<li>不均勻 → hot shard、實際容量達不到名義</li>
<li>4.4+ 可以 reshard、但仍是大手術</li>
</ul>
<p><strong>2. Replica set 是 HA 基礎</strong>：</p>
<ul>
<li>至少 3 個 member（1 primary + 2 secondary）</li>
<li>secondary 可 read（read preference）但要注意 lag</li>
<li>failover 通常 &lt; 30 秒</li>
</ul>
<p><strong>3. Atlas managed 服務</strong>：</p>
<ul>
<li>提供 auto-scaling、auto-backup、跨雲部署</li>
<li>Tier 從 M0（free）到 M700（高階）</li>
<li>Atlas Online Archive 自動把舊資料移到便宜 storage</li>
</ul>
<p><strong>4. Index 限制</strong>：</p>
<ul>
<li>單 collection 最多 64 個 index</li>
<li>compound index 有順序敏感（{a:1, b:1} 跟 {b:1, a:1} 不同）</li>
<li>TTL index 自動 expire 過期 document</li>
</ul>
<p><strong>5. Change streams（CDC）</strong>：</p>
<ul>
<li>4.0+ 提供原生 change streams</li>
<li>對接 Kafka / event bus 做 event sourcing</li>
</ul>
<h2 id="anti-recommendation-與升級路由">Anti-recommendation 與升級路由</h2>
<p>MongoDB 的 schema flexibility 會降低早期建模成本，也會把 schema governance 延後到 production。這一段先說何時維持 document model，再說何時升級 Atlas、sharding、Cosmos DB、DynamoDB 或 SQL。</p>
<table>
  <thead>
      <tr>
          <th>機制 / 路線</th>
          <th>維持簡單設計的條件</th>
          <th>升級訊號</th>
          <th>主要引用路徑</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>單一 replica set</td>
          <td>document size 穩定、working set 可控、primary 寫入足夠</td>
          <td>storage / write / working set 接近上限、failover 演練不足</td>
          <td><a href="/blog/backend/knowledge-cards/replication-lag/" data-link-title="Replication Lag" data-link-desc="說明資料副本落後正式來源多久，以及它如何影響讀取正確性">Replication Lag</a>、<a href="/blog/backend/knowledge-cards/rpo/" data-link-title="RPO" data-link-desc="說明恢復點目標如何定義可接受資料損失範圍">RPO</a></td>
      </tr>
      <tr>
          <td>Atlas managed</td>
          <td>團隊仍能管理 backup、upgrade、monitoring 與 scaling</td>
          <td>DBA / SRE 責任想轉交平台、跨雲部署與 backup 成為主要壓力</td>
          <td><a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">Audit Log</a>、<a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a></td>
      </tr>
      <tr>
          <td>Sharded cluster</td>
          <td>single replica set 還能承擔容量與維護窗口</td>
          <td>shard key 穩定、tenant / user / region 可分、hot shard 可觀測</td>
          <td><a href="/blog/backend/knowledge-cards/database-sharding/" data-link-title="Database Sharding" data-link-desc="說明資料庫如何依 shard key 分散資料、路由請求與承擔跨 shard 查詢成本">Database Sharding</a>、<a href="/blog/backend/knowledge-cards/hot-partition/" data-link-title="Hot Partition" data-link-desc="說明分散式 KV / OLTP 中、單一 partition 流量遠超其他的容量問題">Hot Partition</a></td>
      </tr>
      <tr>
          <td>Cosmos DB MongoDB API</td>
          <td>Azure 只是部署選項，原生 MongoDB 行為仍重要</td>
          <td>Azure global distribution、multi-region write 或 RU governance 成主題</td>
          <td><a href="/blog/backend/01-database/vendors/cosmosdb/" data-link-title="Azure Cosmos DB" data-link-desc="全球分散式 multi-model DB、5 個 consistency levels、Microsoft 自家 dogfood 證據">Cosmos DB vendor</a></td>
      </tr>
      <tr>
          <td>DynamoDB / KV</td>
          <td>query 仍需要 document traversal 與 aggregation</td>
          <td>access pattern 固定、sub-10ms p99、connection-free scaling 成主題</td>
          <td><a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB vendor</a></td>
      </tr>
      <tr>
          <td>PostgreSQL</td>
          <td>document 是主要資料形狀</td>
          <td>JOIN-heavy、transaction-heavy、schema 約束是主要價值</td>
          <td><a href="/blog/backend/01-database/vendors/postgresql/" data-link-title="PostgreSQL" data-link-desc="多用途 OLTP 主流關聯式資料庫、MVCC、豐富 SQL 特性、是 Aurora / Cosmos DB / Spanner / CockroachDB / Aurora DSQL 的相容目標">PostgreSQL vendor</a></td>
      </tr>
  </tbody>
</table>
<p>MongoDB 的簡單路徑是先把 document boundary 寫清楚。資料可以彈性演進，但 application 仍要知道哪些欄位是正式契約、哪些欄位只是相容期，並用 validation、migration 與 data quality check 管住版本漂移。</p>
<p>Sharding 的升級路徑要等 shard key 與 query shape 足夠穩定。過早切 shard 會把 aggregation、transaction 與 index 成本提前放大；過晚切 shard 則會讓 resharding、chunk migration 與 balancer 壓力進入 production 高峰期。</p>
<h2 id="deep-article已完成">Deep article（已完成）</h2>
<p>本批 6 篇 deep article 已完成、覆蓋 MongoDB 從 schema 設計到 production 跨層架構的核心 production 議題：</p>
<table>
  <thead>
      <tr>
          <th>主題</th>
          <th>文章</th>
          <th>對應 production 議題</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Schema contract 該放 DB 層 validator 還是 app 層 abstraction</td>
          <td><a href="schema-design-pattern/">schema-design-pattern</a></td>
          <td>Toyota polymorphic governance、Forbes abstraction layer</td>
      </tr>
      <tr>
          <td>Shard key 選型 + 單 cluster vs 多 cluster blast radius</td>
          <td><a href="shard-key-selection/">shard-key-selection</a></td>
          <td>Toyota 20 DB blast radius、跟 DynamoDB 可逆性對比</td>
      </tr>
      <tr>
          <td>Read preference + causal session 跟 cache 層 freshness token</td>
          <td><a href="replica-set-read-preference/">replica-set-read-preference</a></td>
          <td>DB 層 + cache 層讀後一致性兩層合用</td>
      </tr>
      <tr>
          <td>Aggregation pipeline 順序 / index / memory boundary</td>
          <td><a href="aggregation-pipeline-optimization/">aggregation-pipeline-optimization</a></td>
          <td>report dashboard 跑爆 primary 的 anti-pattern 治理</td>
      </tr>
      <tr>
          <td>Change streams resume token + Kafka connector 治理</td>
          <td><a href="change-streams-kafka/">change-streams-kafka</a></td>
          <td>at-least-once 語義 + idempotency + resume token 過期防護</td>
      </tr>
      <tr>
          <td>Driver × deployment × cache × predictive scaling 三層協作</td>
          <td><a href="connection-management-and-cache-layer/">connection-management-and-cache-layer</a></td>
          <td>Coinbase mongobetween + freshness token + ML 預測擴容三件套</td>
      </tr>
  </tbody>
</table>
<p>跨 vendor entry：先看 <a href="../db3-vendor-selection/">DB3 vendor selection</a>（MongoDB / DynamoDB / Cosmos DB 三方選型 + workload shape 前置判讀），再進本 vendor 的 deep article。</p>
<h2 id="後續擴充仍待補">後續擴充（仍待補）</h2>
<ul>
<li>Index 設計跟覆蓋</li>
<li>從自管 MongoDB 遷到 Atlas</li>
<li>從 MongoDB 遷到 Cosmos DB MongoDB API（保留 document model）</li>
<li>從 MongoDB 遷到 DynamoDB（access pattern 需要重設計）</li>
<li>Queryable encryption（CSFLE）</li>
</ul>
<h2 id="案例對照">案例對照</h2>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 MongoDB 的關係</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/09-performance-capacity/cases/microsoft-365-cosmos-db-analytics/" data-link-title="9.C30 Microsoft 365：從 MongoDB 遷移到 Cosmos DB 的分析平台" data-link-desc="Microsoft 365 把使用分析平台從 MongoDB 遷移到 Cosmos DB、planet-scale 全球分散式分析">9.C30 Microsoft 365</a></td>
          <td>從 MongoDB 遷到 Cosmos DB MongoDB API、planet-scale analytics</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/09-performance-capacity/cases/coinbase-mongodb-document-platform/" data-link-title="9.C36 Coinbase：MongoDB 撐 Ruby 單體 &#43; 1.5M reads/sec identity 服務" data-link-desc="Coinbase 以 MongoDB 為主資料層、自建 mongobetween connection proxy、users 服務在加密貨幣 surge 時撐 1.5M reads/sec">9.C36 Coinbase</a></td>
          <td>MongoDB 為主資料層、自建 mongobetween 解決 Ruby 連線爆炸、users 服務 1.5M reads/sec</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/09-performance-capacity/cases/forbes-mongodb-atlas-multi-cloud-migration/" data-link-title="9.C37 Forbes：自管 MongoDB → Atlas on GCP、build 時間 25 → 9 分鐘" data-link-desc="Forbes 把自管 MongoDB 遷到 Atlas on Google Cloud、6 個月完成、build 25 → 9 分鐘、120M 不重複訪客單月承接">9.C37 Forbes</a></td>
          <td>自管 MongoDB → Atlas on GCP、6 個月遷完、build 25→9 分鐘、120M MAU</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/09-performance-capacity/cases/toyota-connected-mongodb-telematics-iot/" data-link-title="9.C38 Toyota Connected：MongoDB Atlas 撐 900 萬車輛 telematics、月 180 億 transaction" data-link-desc="Toyota Connected 用 MongoDB Atlas 撐 Safety Connect 900 萬車、月 180 億 transaction、緊急訊號 3 秒內到 agent">9.C38 Toyota Connected</a></td>
          <td>Atlas 撐 900 萬車 telematics、月 180 億 transaction、緊急訊號 3 秒內到 agent</td>
      </tr>
  </tbody>
</table>
<p>MongoDB case 的讀法分三組：</p>
<ul>
<li><strong>作為 production 主角持續演進</strong>（Coinbase、Toyota Connected）：document model 撐住核心 OLTP / IoT、配 connection proxy / cache / event-driven 處理擴展周邊。</li>
<li><strong>自管 → managed 遷移</strong>（Forbes）：同 document model、換託管模式、ROI 集中在 DBA 責任轉移跟跨雲彈性、不是性能改善。</li>
<li><strong>遷出 MongoDB 保留 API</strong>（Microsoft 365）：document model 保留、底層換到 Cosmos DB MongoDB API、換取 Azure global distribution。</li>
</ul>
<p>讀 case 時要區分 MongoDB 在「主角 / 遷入 / 遷出」三種位置的差異，三種位置揭露的工程議題完全不同。</p>
<h2 id="常見陷阱">常見陷阱</h2>
<ul>
<li><strong>schema 長期 schema-less</strong>：production 出現 data inconsistency、難 query</li>
<li><strong>shard key 用 _id（自增）</strong>：寫入全集中在最後一個 shard</li>
<li><strong>$lookup 過度使用</strong>：跨 collection JOIN-heavy workload 應在 schema design 時 denormalize 或回 SQL</li>
<li><strong>index 太多</strong>：寫吞吐被拖垮、定期 review 未用 index</li>
<li><strong>secondary read 不檢查 lag</strong>：用戶讀到 stale data</li>
<li><strong>不規劃 Atlas tier upgrade 路徑</strong>：流量上來才發現 tier 跟不上、緊急升級費用高</li>
</ul>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>完整 T1 對照：<a href="/blog/backend/01-database/vendors/" data-link-title="資料庫 Vendor 清單" data-link-desc="規劃 SQL、managed SQL、document、KV 與 distributed SQL 的服務頁撰寫順序與教學大綱">01-database vendors index</a></li>
<li>平行：<a href="/blog/backend/01-database/vendors/cosmosdb/" data-link-title="Azure Cosmos DB" data-link-desc="全球分散式 multi-model DB、5 個 consistency levels、Microsoft 自家 dogfood 證據">Cosmos DB vendor</a>（MongoDB API replacement）、<a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB vendor</a>（KV alternative）</li>
<li>上游：<a href="/blog/backend/01-database/schema-design/" data-link-title="1.2 Schema Design 與資料建模" data-link-desc="整理 table、index、key、partition、denormalization 與命名規則">1.2 schema design</a>、<a href="/blog/backend/01-database/kv-document-capacity-planning/" data-link-title="1.10 KV / Document DB 容量規劃" data-link-desc="DynamoDB / Cosmos DB / Bigtable / MongoDB 等 KV / Document DB 的容量設計、partition key 取捨、capacity mode 選擇">1.10 KV / Document DB 容量規劃</a></li>
<li>下游：<a href="/blog/backend/01-database/large-scale-db-migration/" data-link-title="1.12 大規模 DB 遷移實戰" data-link-desc="跨 DB 遷移的 dual-write、[shadow read](/backend/knowledge-cards/shadow-read/)、cutover、rollback 流程 — 從實戰案例提煉的工程做法">1.12 大規模 DB 遷移實戰</a>（MongoDB 遷出範例）</li>
<li>跨模組：<a href="/blog/backend/09-performance-capacity/capacity-planning/" data-link-title="9.6 容量規劃模型" data-link-desc="peak forecast、headroom budget、growth curve、autoscaling sizing">9.6 容量規劃模型</a>、<a href="/blog/backend/09-performance-capacity/saturation-discovery/" data-link-title="9.4 Saturation Discovery" data-link-desc="找出 throughput plateau 與 latency knee 的方法">9.4 Saturation Discovery</a>（shard key 跟 hot shard）</li>
<li>官方：<a href="https://www.mongodb.com/docs/manual/">MongoDB Manual</a>、<a href="https://www.mongodb.com/atlas">MongoDB Atlas</a></li>
</ul>
]]></content:encoded></item><item><title>Firestore</title><link>https://tarrragon.github.io/blog/backend/01-database/vendors/firestore/</link><pubDate>Tue, 16 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/01-database/vendors/firestore/</guid><description>&lt;p>Firestore 是 Google 的 serverless document database、承擔 mobile app 與 SPA 的正式狀態與多裝置即時同步責任。它的資料形狀是 collection 下的 document、存取模型是 client 端用 SDK 直連、授權靠 Security Rules，而不是經過自己寫的後端服務。Firestore 同時是 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/baas/" data-link-title="BaaS（Backend as a Service）" data-link-desc="說明把認證、資料庫、檔案儲存、推播打包成現成模組、由前端 SDK 直連的後端交付形態">Firebase&lt;/a> bundle 的資料層、也能在 Google Cloud 上單獨使用；本頁從&lt;strong>資料層 vendor 視角&lt;/strong>說明它承擔什麼狀態責任、為哪種查詢付成本、何時撞牆該遷往自建。要不要採用 BaaS 這種交付形態本身、是更上層的決策，見 &lt;a href="https://tarrragon.github.io/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">0.21 交付形態選型&lt;/a> 與 &lt;a href="https://tarrragon.github.io/blog/backend/00-service-selection/capability-buy-vs-build/" data-link-title="0.22 能力級買 vs 建：feature-as-a-service 與 BaaS bundle 選型" data-link-desc="在交付形態決定整個系統要不要自建之後、逐能力判斷該外包還是自建：辨識 managed 基礎設施、feature SaaS 與 BaaS bundle 三種外包深度、no-code 到 dev-tool 的服務光譜、買 vs 建判準與權重浮動、整合接縫與遷出代價">0.22 能力級買 vs 建&lt;/a>。&lt;/p>
&lt;p>官方文件路由：&lt;a href="https://firebase.google.com/docs/firestore">Firestore documentation&lt;/a>、&lt;a href="https://firebase.google.com/docs/firestore/data-model">Firestore data model&lt;/a>、&lt;a href="https://firebase.google.com/docs/firestore/pricing">Firestore pricing&lt;/a>；本頁時間敏感的計費與限制 claim 以官方為準、最後檢查日 2026-06-16。&lt;/p>
&lt;h2 id="教學路線client-直連的-document-正式狀態">教學路線：client 直連的 document 正式狀態&lt;/h2>
&lt;p>Firestore 服務頁的教學目標是把「前端直接讀寫資料庫」這個存取模型的責任說清楚。讀者讀完後要能判斷 Firestore 何時是合適的正式狀態，何時因為查詢形狀、成本曲線或授權複雜度該轉向自建後端配 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/postgresql/" data-link-title="PostgreSQL" data-link-desc="多用途 OLTP 主流關聯式資料庫、MVCC、豐富 SQL 特性、是 Aurora / Cosmos DB / Spanner / CockroachDB / Aurora DSQL 的相容目標">PostgreSQL&lt;/a> 或留在 document model 換 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mongodb/" data-link-title="MongoDB" data-link-desc="Document database 代表、Atlas managed、跨雲可用、許多大規模平台從 MongoDB 起家">MongoDB&lt;/a>。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>學習段&lt;/th>
 &lt;th>核心問題&lt;/th>
 &lt;th>對應段落&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>Client-direct state&lt;/td>
 &lt;td>前端用 SDK 直連、授權下沉到 Security Rules 後責任邊界在哪&lt;/td>
 &lt;td>定位、存取模型&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Document shape&lt;/td>
 &lt;td>collection / document / subcollection 如何決定查詢能力&lt;/td>
 &lt;td>資料形狀、適用場景&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Query boundary&lt;/td>
 &lt;td>為什麼跨 collection 報表查不出來、index 與查詢限制如何約束建模&lt;/td>
 &lt;td>不適用場景、常見陷阱&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>Realtime / offline&lt;/td>
 &lt;td>snapshot listener 與 offline persistence 解哪類多裝置同步問題&lt;/td>
 &lt;td>適用場景、跟其他 vendor 的取捨&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>替代路由&lt;/td>
 &lt;td>撞到報表、成本或授權牆時、遷往自建 relational 或換 document vendor&lt;/td>
 &lt;td>下一步路由、遷移 playbook&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="定位serverless-document-store--baas-資料層">定位：serverless document store + BaaS 資料層&lt;/h2>
&lt;p>Firestore 跟 &lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/mongodb/" data-link-title="MongoDB" data-link-desc="Document database 代表、Atlas managed、跨雲可用、許多大規模平台從 MongoDB 起家">MongoDB&lt;/a>、&lt;a href="https://tarrragon.github.io/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB&lt;/a> 同屬 NoSQL document / KV 家族，但承擔的責任層級不同：&lt;/p>
&lt;ul>
&lt;li>資料組織成 collection 下的 document，document 可巢狀 subcollection，單 document 上限 1 MiB&lt;/li>
&lt;li>沒有 server 端 JOIN，跨 collection 的關聯要靠 application 多次查詢自己組、或在寫入時反正規化&lt;/li>
&lt;li>存取模型以 client SDK 直連為主，授權寫在 Security Rules（一套規則 DSL），而不是後端 API 的權限中介層&lt;/li>
&lt;li>兩種營運模式：Firestore Native mode（行動 / web、含 realtime 與 offline）與 Datastore mode（server 端、相容舊 Datastore）&lt;/li>
&lt;/ul>
&lt;p>傳統定位：Firebase 行動 app 與 SPA 的後端資料層、MVP 快速驗證期、多裝置即時同步的產品。&lt;/p></description><content:encoded><![CDATA[<p>Firestore 是 Google 的 serverless document database、承擔 mobile app 與 SPA 的正式狀態與多裝置即時同步責任。它的資料形狀是 collection 下的 document、存取模型是 client 端用 SDK 直連、授權靠 Security Rules，而不是經過自己寫的後端服務。Firestore 同時是 <a href="/blog/backend/knowledge-cards/baas/" data-link-title="BaaS（Backend as a Service）" data-link-desc="說明把認證、資料庫、檔案儲存、推播打包成現成模組、由前端 SDK 直連的後端交付形態">Firebase</a> bundle 的資料層、也能在 Google Cloud 上單獨使用；本頁從<strong>資料層 vendor 視角</strong>說明它承擔什麼狀態責任、為哪種查詢付成本、何時撞牆該遷往自建。要不要採用 BaaS 這種交付形態本身、是更上層的決策，見 <a href="/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">0.21 交付形態選型</a> 與 <a href="/blog/backend/00-service-selection/capability-buy-vs-build/" data-link-title="0.22 能力級買 vs 建：feature-as-a-service 與 BaaS bundle 選型" data-link-desc="在交付形態決定整個系統要不要自建之後、逐能力判斷該外包還是自建：辨識 managed 基礎設施、feature SaaS 與 BaaS bundle 三種外包深度、no-code 到 dev-tool 的服務光譜、買 vs 建判準與權重浮動、整合接縫與遷出代價">0.22 能力級買 vs 建</a>。</p>
<p>官方文件路由：<a href="https://firebase.google.com/docs/firestore">Firestore documentation</a>、<a href="https://firebase.google.com/docs/firestore/data-model">Firestore data model</a>、<a href="https://firebase.google.com/docs/firestore/pricing">Firestore pricing</a>；本頁時間敏感的計費與限制 claim 以官方為準、最後檢查日 2026-06-16。</p>
<h2 id="教學路線client-直連的-document-正式狀態">教學路線：client 直連的 document 正式狀態</h2>
<p>Firestore 服務頁的教學目標是把「前端直接讀寫資料庫」這個存取模型的責任說清楚。讀者讀完後要能判斷 Firestore 何時是合適的正式狀態，何時因為查詢形狀、成本曲線或授權複雜度該轉向自建後端配 <a href="/blog/backend/01-database/vendors/postgresql/" data-link-title="PostgreSQL" data-link-desc="多用途 OLTP 主流關聯式資料庫、MVCC、豐富 SQL 特性、是 Aurora / Cosmos DB / Spanner / CockroachDB / Aurora DSQL 的相容目標">PostgreSQL</a> 或留在 document model 換 <a href="/blog/backend/01-database/vendors/mongodb/" data-link-title="MongoDB" data-link-desc="Document database 代表、Atlas managed、跨雲可用、許多大規模平台從 MongoDB 起家">MongoDB</a>。</p>
<table>
  <thead>
      <tr>
          <th>學習段</th>
          <th>核心問題</th>
          <th>對應段落</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Client-direct state</td>
          <td>前端用 SDK 直連、授權下沉到 Security Rules 後責任邊界在哪</td>
          <td>定位、存取模型</td>
      </tr>
      <tr>
          <td>Document shape</td>
          <td>collection / document / subcollection 如何決定查詢能力</td>
          <td>資料形狀、適用場景</td>
      </tr>
      <tr>
          <td>Query boundary</td>
          <td>為什麼跨 collection 報表查不出來、index 與查詢限制如何約束建模</td>
          <td>不適用場景、常見陷阱</td>
      </tr>
      <tr>
          <td>Realtime / offline</td>
          <td>snapshot listener 與 offline persistence 解哪類多裝置同步問題</td>
          <td>適用場景、跟其他 vendor 的取捨</td>
      </tr>
      <tr>
          <td>替代路由</td>
          <td>撞到報表、成本或授權牆時、遷往自建 relational 或換 document vendor</td>
          <td>下一步路由、遷移 playbook</td>
      </tr>
  </tbody>
</table>
<h2 id="定位serverless-document-store--baas-資料層">定位：serverless document store + BaaS 資料層</h2>
<p>Firestore 跟 <a href="/blog/backend/01-database/vendors/mongodb/" data-link-title="MongoDB" data-link-desc="Document database 代表、Atlas managed、跨雲可用、許多大規模平台從 MongoDB 起家">MongoDB</a>、<a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB</a> 同屬 NoSQL document / KV 家族，但承擔的責任層級不同：</p>
<ul>
<li>資料組織成 collection 下的 document，document 可巢狀 subcollection，單 document 上限 1 MiB</li>
<li>沒有 server 端 JOIN，跨 collection 的關聯要靠 application 多次查詢自己組、或在寫入時反正規化</li>
<li>存取模型以 client SDK 直連為主，授權寫在 Security Rules（一套規則 DSL），而不是後端 API 的權限中介層</li>
<li>兩種營運模式：Firestore Native mode（行動 / web、含 realtime 與 offline）與 Datastore mode（server 端、相容舊 Datastore）</li>
</ul>
<p>傳統定位：Firebase 行動 app 與 SPA 的後端資料層、MVP 快速驗證期、多裝置即時同步的產品。</p>
<p>資料層視角的定位：一塊 <em>managed serverless document store</em>，把 capacity、replication、failover、scaling 全部交給平台，代價是查詢能力與資料模型沿平台特性生長。</p>
<h2 id="資料形狀與查詢邊界">資料形狀與查詢邊界</h2>
<p>Firestore 為「已知路徑的 document 讀寫」付成本，不為「任意欄位的 ad-hoc 查詢」付成本。這個取向決定了它的甜蜜區與牆：</p>
<ul>
<li>單 document 與單 collection 內的 key-based / 條件查詢高效，且每筆查詢都要有對應 index（單欄 index 自動建立、複合查詢要建 composite index）</li>
<li>查詢結果集的計費與大小跟「讀了幾筆 document」成正比，不是跟「掃了多少」— 一次回 10,000 筆就計 10,000 次 read</li>
<li>缺少 server 端 aggregation pipeline 與 JOIN；跨集合報表（例如「本月各地區訂單金額」）在 Firestore 上要嘛預先把彙總寫成一份 document、要嘛把資料複製到分析系統</li>
<li>沒有原生全文搜尋，全文需求要接專門的 <a href="/blog/backend/knowledge-cards/search-index/" data-link-title="Search Index" data-link-desc="說明搜尋索引如何承擔全文檢索、排序與查詢體驗">search index</a>（Algolia、Elasticsearch / OpenSearch）</li>
</ul>
<p>這條查詢邊界是 Firestore 最容易被低估的設計約束。它不是「功能還沒做」，而是 client 直連 + serverless 計費模型的必然結果：把任意 ad-hoc 查詢開放給前端，等於把不可預測的成本與掃描壓力暴露在公網。建模時要先窮舉 access pattern、再決定 document 結構，跟 <a href="/blog/backend/01-database/vendors/dynamodb/single-table-design-pattern/" data-link-title="DynamoDB Single-Table Design：從適用度前置判讀到 access pattern 反推 PK/SK" data-link-desc="DynamoDB single-table 設計不是「資料表越少越好」，而是 access pattern 反推 PK/SK 跟 GSI；本文先做 DynamoDB 適用度 4 軸前置判讀（PK 天然均勻 / control plane vs data plane / consistency / access pattern 穩定），再展開設計流程、failure modes 與 durable queue 正向用例">DynamoDB single-table design</a> 的 access-pattern-first 思路同源。</p>
<h2 id="一致性realtime-與容量特性">一致性、realtime 與容量特性</h2>
<p><strong>一致性</strong>：</p>
<ul>
<li>單 document 讀寫與「查詢結果在同一 region 內」提供 strong consistency</li>
<li>多 region 部署靠平台複製、跨 region 讀取可能有延遲；一致性語意由平台決定、不可調到自管資料庫那種 isolation level 顆粒</li>
</ul>
<p><strong>Realtime 與 offline</strong>：</p>
<ul>
<li>snapshot listener 讓 client 訂閱 query 結果、資料變更即時推送，是多裝置同步的核心能力</li>
<li>行動 / web SDK 內建 offline persistence，斷線時讀寫本地快取、回線後同步，這是自建 REST API 要額外工程才有的能力</li>
</ul>
<p><strong>容量與寫入熱點</strong>：</p>
<ul>
<li>serverless 自動擴縮，無 connection 概念，前端裝置數不直接轉成資料庫連線壓力</li>
<li>單一 document 的高頻寫入會撞到 contention（官方建議單 document 的持續寫入維持在每秒個位數量級、高頻計數器要用 distributed counter 分片）</li>
<li>寫入吞吐與索引維護成本綁在一起：每多一個 index、寫入就多一份維護成本</li>
</ul>
<p>容量特性的時間敏感數字（每秒寫入軟上限、單 document contention 門檻）以 <a href="https://firebase.google.com/docs/firestore/best-practices">官方 best practices</a> 為準，設計高頻寫入前先查當前限制。</p>
<h2 id="適用場景">適用場景</h2>
<p><strong>1. 行動 app / SPA 的 MVP 後端</strong>：</p>
<ul>
<li>認證接 Firebase Auth、資料存 Firestore、推播接 Cloud Messaging，整個 MVP 沒有自己的後端服務</li>
<li>對應 <a href="/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">0.21</a> BaaS 段的「把後端工程師這個角色延後」</li>
</ul>
<p><strong>2. 多裝置即時同步</strong>：</p>
<ul>
<li>協作筆記、聊天、即時看板這類「一處改、多處即時更新」的產品</li>
<li>snapshot listener + offline persistence 是這類需求的天然形狀</li>
</ul>
<p><strong>3. access pattern 穩定的 document 工作負載</strong>：</p>
<ul>
<li>user profile、設定、feed item、活動紀錄這類讀多寫少、查詢路徑固定的資料</li>
<li>跟 <a href="/blog/backend/knowledge-cards/source-of-truth/" data-link-title="Source of Truth" data-link-desc="說明正式資料來源如何決定資料判斷、修復與一致性責任">source of truth</a> 對齊：Firestore 可以是這些資料的正式狀態</li>
</ul>
<h2 id="不適用場景">不適用場景</h2>
<p><strong>1. 跨實體報表與分析查詢</strong>：</p>
<ul>
<li>跨 collection JOIN、ad-hoc 篩選、彙總統計在 Firestore 上要靠資料複製工程</li>
<li>替代：自建 relational（<a href="/blog/backend/01-database/vendors/postgresql/" data-link-title="PostgreSQL" data-link-desc="多用途 OLTP 主流關聯式資料庫、MVCC、豐富 SQL 特性、是 Aurora / Cosmos DB / Spanner / CockroachDB / Aurora DSQL 的相容目標">PostgreSQL</a>）或把資料同步進分析系統</li>
</ul>
<p><strong>2. 成本對流量敏感的高讀取場景</strong>：</p>
<ul>
<li>計費隨 document read / write / delete 線性成長，高流量下可能超過自建</li>
<li>替代：自管資料庫 + 應用層 <a href="/blog/backend/02-cache-redis/" data-link-title="模組二：快取與 Redis" data-link-desc="整理快取策略、Redis 資料型別與分散式狀態輔助能力">cache</a>，把熱讀取的單位成本壓下來</li>
</ul>
<p><strong>3. 複雜授權需要可測試的控制面</strong>：</p>
<ul>
<li>client 直連模型把授權全塞進 Security Rules，規則長到難以 review / 測試時，控制面風險升高</li>
<li>替代：把授權拉回後端 API 中介層（自建後端 + 任意資料庫）</li>
</ul>
<p><strong>4. 強一致的多實體交易</strong>：</p>
<ul>
<li>Firestore 有 transaction 與 batch write，但跨大量 document 的複雜交易不是它的主場</li>
<li>替代：relational database 的多表交易</li>
</ul>
<h2 id="跟其他-vendor-的取捨">跟其他 vendor 的取捨</h2>
<p><strong>vs MongoDB（document 對 document）</strong>：</p>
<ul>
<li>Firestore：serverless、client 直連、realtime listener、GCP / Firebase 綁定、查詢能力受限</li>
<li>MongoDB：查詢與 aggregation 彈性高、跨雲、要自管或用 Atlas managed、走後端中介存取</li>
<li>選 Firestore：行動 / 即時同步 / 想省整層後端</li>
<li>選 MongoDB：document model 但要彈性查詢、aggregation、跨雲可攜，見 <a href="/blog/backend/01-database/vendors/db3-vendor-selection/" data-link-title="DB3 Vendor Selection：document / KV / multi-model 三方選型 &#43; workload shape 前置判讀" data-link-desc="MongoDB / DynamoDB / Cosmos DB 三家 NoSQL 選型 entry point：workload shape × access pattern × consistency 三軸前置判讀、migration path 三型、federated DB 視角、三 vendor 對比 10 軸">db3 vendor selection</a></li>
</ul>
<p><strong>vs DynamoDB（serverless NoSQL 對 serverless NoSQL）</strong>：</p>
<ul>
<li>Firestore：GCP / Firebase 生態、內建 realtime 與 offline、client 直連為主</li>
<li>DynamoDB：AWS 生態、access-pattern-first KV、通常走後端整合、streams 接事件驅動</li>
<li>兩者的 access-pattern-first 建模思路相近，差別在生態與 client 直連的有無</li>
</ul>
<p><strong>vs SQLite（行動端的反向選擇）</strong>：</p>
<ul>
<li>Firestore：雲端 store、自動多裝置 sync、realtime</li>
<li>SQLite：embedded、offline-first、無 sync（見 <a href="/blog/backend/01-database/vendors/sqlite/" data-link-title="SQLite" data-link-desc="embedded、單檔案、test / CLI / edge 場景的標準選擇、近年因 Cloudflare D1 / Turso 等服務復興">SQLite vendor</a>）</li>
<li>選 Firestore：需要跨裝置同步與即時更新</li>
<li>選 SQLite：純單機 / offline、不需要雲端同步</li>
</ul>
<p><strong>vs Supabase（BaaS bundle 的另一條路）</strong>：</p>
<ul>
<li>Firestore：document model、Google 的 BaaS bundle 資料層</li>
<li>Supabase：底層是 PostgreSQL（relational）、開源 BaaS bundle，遷出時資料是標準 SQL</li>
<li>兩者都是 client 直連 + 規則授權的 BaaS 形狀，差別在資料模型（document vs relational）與遷出時的資料可攜性；Supabase 的資料層判讀見 <a href="/blog/backend/01-database/vendors/postgresql/managed-pg-comparison/" data-link-title="Managed PostgreSQL Comparison" data-link-desc="RDS PostgreSQL、Aurora PostgreSQL、Cloud SQL、Azure Database for PostgreSQL、Neon、Supabase、Crunchy Bridge 的責任邊界比較">Managed PostgreSQL 比較</a>，選型層錨點見 <a href="/blog/backend/00-service-selection/capability-buy-vs-build/" data-link-title="0.22 能力級買 vs 建：feature-as-a-service 與 BaaS bundle 選型" data-link-desc="在交付形態決定整個系統要不要自建之後、逐能力判斷該外包還是自建：辨識 managed 基礎設施、feature SaaS 與 BaaS bundle 三種外包深度、no-code 到 dev-tool 的服務光譜、買 vs 建判準與權重浮動、整合接縫與遷出代價">0.22</a></li>
</ul>
<h2 id="容量規劃要點">容量規劃要點</h2>
<p><strong>1. access pattern 先於 document 結構</strong>：</p>
<ul>
<li>列出 application 對資料的所有讀寫路徑、再設計 collection / document 形狀</li>
<li>access pattern 沒想清楚就建模，後面報表查不出來要重做</li>
</ul>
<p><strong>2. 反正規化換查詢效率</strong>：</p>
<ul>
<li>為了避免跨 collection 多次查詢，常把關聯資料冗餘寫進同一 document</li>
<li>代價是寫入時要維護多份副本的一致性，對應 <a href="/blog/backend/01-database/reconciliation-data-repair/" data-link-title="1.9 Reconciliation 與 Data Repair" data-link-desc="資料不一致的分類、偵測模式、修復策略、audit trail、跟 backup / PITR 整合">1.9 Reconciliation</a></li>
</ul>
<p><strong>3. index 與寫入成本綁定</strong>：</p>
<ul>
<li>複合查詢要先建 composite index、否則查詢直接失敗</li>
<li>每個 index 增加寫入維護成本，移除用不到的 index 是容量優化的一環</li>
</ul>
<p><strong>4. 高頻寫入用 distributed counter</strong>：</p>
<ul>
<li>單一 document 撞到 contention 上限時，把計數拆成多個 shard document 再彙總</li>
</ul>
<p><strong>5. 成本以 document 數計，不以掃描量計</strong>：</p>
<ul>
<li>容量估算要算「每個畫面 / API 觸發幾次 read」、乘上日活與頻率</li>
<li>把熱讀取移到 <a href="/blog/backend/02-cache-redis/cache-aside/" data-link-title="2.2 cache aside 與失效策略" data-link-desc="整理 read-through 思路、cache miss 與 invalidation">應用層快取</a> 是壓低 read 計費的主要手段</li>
</ul>
<h2 id="常見陷阱">常見陷阱</h2>
<ul>
<li><strong>把 Firestore 當關聯式用</strong>：規劃了一堆需要 JOIN 的 collection、上線後跨集合查詢全靠 client 自己組、latency 與 read 成本爆炸</li>
<li><strong>報表需求到了才發現查不出來</strong>：老闆要月報、Firestore 沒有 aggregation pipeline、被迫臨時搭資料複製管線</li>
<li><strong>Security Rules 長到沒人敢改</strong>：授權全寫在規則 DSL、沒有版本控制與測試、變更時靠人工推敲</li>
<li><strong>單 document 當高頻計數器</strong>：直播按讚 / 即時計數寫爆單一 document 的 contention 上限</li>
<li><strong>忽略 read 計費規模</strong>：list 畫面一次回上千筆、每次重整都計上千次 read、帳單月底才浮現</li>
</ul>
<h2 id="deep-article-章節群">Deep article 章節群</h2>
<p>Firestore overview 負責第一輪服務判斷；vendor 特有機制的設定、踩坑與容量規劃拆成 deep article。下表是目前已建立的實作層教材，讀法是先讀 overview 判斷服務適配，再按撞到的壓力選 deep article。</p>
<table>
  <thead>
      <tr>
          <th>機制</th>
          <th>文件</th>
          <th>教學責任</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>授權控制面</td>
          <td><a href="/blog/backend/01-database/vendors/firestore/security-rules-authz-modeling/" data-link-title="Firestore Security Rules 授權建模與可測試化：把規則當程式碼治理" data-link-desc="Firestore client 直連模型把整個授權控制面壓在 Security Rules 這套 DSL 裡；本文展開規則的求值模型、把授權拆成可組合 function、用 emulator 寫單元測試、五個把規則寫成資安漏洞的 production 踩坑，以及規則複雜度撞牆時把授權拉回後端的邊界">Security Rules 授權建模與可測試化</a></td>
          <td>規則求值模型、可組合 function、emulator 單元測試、把規則當程式碼治理</td>
      </tr>
      <tr>
          <td>高頻寫入</td>
          <td><a href="/blog/backend/01-database/vendors/firestore/distributed-counter-high-frequency-write/" data-link-title="Firestore 高頻寫入與 distributed counter：單 document contention 邊界與分片計數" data-link-desc="Firestore 單一 document 有持續寫入的軟上限、高頻計數寫爆 contention 是常見事故；本文展開寫入 contention 的成因、distributed counter 分片計數的實作與讀取彙總、shard 數量與讀寫成本的取捨、五個高頻寫入踩坑，以及計數需求超過分片能處理時改走外部聚合的邊界">高頻寫入與 distributed counter</a></td>
          <td>單 document contention 邊界、分片計數、shard 數與讀寫成本取捨</td>
      </tr>
      <tr>
          <td>資料建模</td>
          <td><a href="/blog/backend/01-database/vendors/firestore/denormalization-fanout-consistency/" data-link-title="Firestore document 反正規化與一致性維護：fan-out write、副本同步與資料修復" data-link-desc="Firestore 沒有 JOIN，查詢能力逼著把關聯資料反正規化複製多份；本文展開反正規化的建模決策、fan-out write 維護副本一致、batch 與 transaction 的選擇、五個副本不一致的 production 踩坑，以及反正規化複雜到該回關聯式的邊界">document 反正規化與一致性維護</a></td>
          <td>反正規化決策、fan-out write、副本同步、不一致修復</td>
      </tr>
      <tr>
          <td>即時同步</td>
          <td><a href="/blog/backend/01-database/vendors/firestore/realtime-listener-fanout-cost/" data-link-title="Firestore realtime listener 扇出與成本：snapshot 訂閱、re-read 計費與連線規模" data-link-desc="Firestore 的 snapshot listener 提供即時同步、但訂閱的扇出、查詢結果變動的 re-read 計費與連線數會在規模下變成成本與效能瓶頸；本文展開 listener 的推送模型、訂閱範圍設計、五個 realtime 成本踩坑，以及即時需求超過 listener 該換推送架構的邊界">realtime listener 扇出與成本</a></td>
          <td>snapshot 推送模型、訂閱範圍設計、re-read 計費、連線規模</td>
      </tr>
  </tbody>
</table>
<p>讀法路由：撞到資料外洩 / 越權，讀 Security Rules；撞到熱門事件寫爆計數，讀 distributed counter；改一筆要連動改一千筆，讀反正規化；即時功能帳單失控，讀 realtime listener。撞到報表 / 成本 / 授權整體性的牆，走 <a href="/blog/backend/01-database/vendors/firestore/migrate-to-relational/" data-link-title="從 Firestore 遷往自建 relational：撞牆驅動的 Type E 重建模、存取模型反轉與並行期" data-link-desc="Firestore → 自建後端 &#43; relational 不是匯資料而是反轉存取模型：client 直連變 API 中介、Security Rules 授權變後端授權、document 反正規化變正規 schema、realtime listener 與 offline 同步要重建；本文走 Type E paradigm shift 結構、展開為何字面遷移不成立、哪些該遷哪些先留、dual-write &#43; shadow read 階段化與遷出代價判讀">遷往自建 relational</a>。</p>
<h2 id="hands-on-操作演練">Hands-on 操作演練</h2>
<p>deep article 講機制判讀，<a href="/blog/backend/01-database/vendors/firestore/hands-on/" data-link-title="Firestore Hands-on 操作路線" data-link-desc="用 Firebase Emulator Suite 在本地演練 Firestore：emulator quickstart、Security Rules 單元測試、distributed counter 分片計數，全程零雲端成本、可重跑、產出可驗證 artifact">Hands-on 操作路線</a> 把機制轉成可在本地 <a href="https://firebase.google.com/docs/emulator-suite">Firebase Emulator</a> 跑的演練——零雲端成本、可重跑、產出可驗證 artifact。三個 lab：<a href="/blog/backend/01-database/vendors/firestore/hands-on/local-emulator-quickstart/" data-link-title="Firestore Local Emulator Quickstart" data-link-desc="用 Firebase CLI 啟動 Firestore emulator、寫 firestore.rules、用 admin SDK seed 資料、跑 query baseline 與 cleanup，建立後續 Security Rules 與 distributed counter lab 共用的本地環境">emulator quickstart</a>（建立共用環境）、<a href="/blog/backend/01-database/vendors/firestore/hands-on/security-rules-test-lab/" data-link-title="Firestore Security Rules Test Lab" data-link-desc="用 @firebase/rules-unit-testing 在 emulator 上把 Security Rules 寫成自動化測試：放行 / 越權拒絕 / 未登入拒絕 / 欄位竄改拒絕四類斷言、firebase emulators:exec 在 CI 跑、把規則測試接進 release gate">Security Rules test lab</a>（規則自動化測試 + 接 release gate）、<a href="/blog/backend/01-database/vendors/firestore/hands-on/distributed-counter-lab/" data-link-title="Firestore Distributed Counter Lab" data-link-desc="在 emulator 上實作 distributed counter：建立 N 個 shard、隨機分片寫入、觀察 shard 分佈是否均勻、讀取彙總驗證總和正確，並說明 contention 本身是 emulator 不模擬的 production 特性">distributed counter lab</a>（分片計數機制驗證）。lab 全程標明 emulator 驗得了什麼（功能行為、規則求值）、驗不了什麼（計費、寫入軟上限要回雲端）。</p>
<h2 id="已知-limitation-與後續路由">已知 limitation 與後續路由</h2>
<p>Firestore overview 完成服務判斷、資料形狀、查詢邊界與替代路由；deep article 章節群覆蓋授權、高頻寫入、反正規化與即時同步四個機制；hands-on 章節群提供 emulator 演練。後續可補的方向：offline persistence 的衝突解決深入、realtime listener 在雲端的成本量測 lab（emulator 不計費、要在雲端 staging 跑）。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>完整 T1 對照：<a href="/blog/backend/01-database/vendors/" data-link-title="資料庫 Vendor 清單" data-link-desc="規劃 SQL、managed SQL、document、KV 與 distributed SQL 的服務頁撰寫順序與教學大綱">01-database vendors index</a></li>
<li>同類對比：<a href="/blog/backend/01-database/vendors/mongodb/" data-link-title="MongoDB" data-link-desc="Document database 代表、Atlas managed、跨雲可用、許多大規模平台從 MongoDB 起家">MongoDB vendor</a>（彈性查詢 document）/ <a href="/blog/backend/01-database/vendors/dynamodb/" data-link-title="DynamoDB" data-link-desc="AWS managed key-value、partition-based scaling、9000 萬 RPS sustained 實戰證據">DynamoDB vendor</a>（access-pattern-first KV）/ <a href="/blog/backend/01-database/vendors/db3-vendor-selection/" data-link-title="DB3 Vendor Selection：document / KV / multi-model 三方選型 &#43; workload shape 前置判讀" data-link-desc="MongoDB / DynamoDB / Cosmos DB 三家 NoSQL 選型 entry point：workload shape × access pattern × consistency 三軸前置判讀、migration path 三型、federated DB 視角、三 vendor 對比 10 軸">db3 vendor selection</a>（document / KV / multi-model 三方選型）</li>
<li>遷出方向：<a href="/blog/backend/01-database/vendors/firestore/migrate-to-relational/" data-link-title="從 Firestore 遷往自建 relational：撞牆驅動的 Type E 重建模、存取模型反轉與並行期" data-link-desc="Firestore → 自建後端 &#43; relational 不是匯資料而是反轉存取模型：client 直連變 API 中介、Security Rules 授權變後端授權、document 反正規化變正規 schema、realtime listener 與 offline 同步要重建；本文走 Type E paradigm shift 結構、展開為何字面遷移不成立、哪些該遷哪些先留、dual-write &#43; shadow read 階段化與遷出代價判讀">Firestore → 自建 relational</a>（撞到報表 / 成本 / 授權牆後的 Type E 重建模 playbook）</li>
<li>操作演練：<a href="/blog/backend/01-database/vendors/firestore/hands-on/" data-link-title="Firestore Hands-on 操作路線" data-link-desc="用 Firebase Emulator Suite 在本地演練 Firestore：emulator quickstart、Security Rules 單元測試、distributed counter 分片計數，全程零雲端成本、可重跑、產出可驗證 artifact">Firestore Hands-on</a>（emulator quickstart、Security Rules 測試、distributed counter lab）</li>
<li>容量背景：<a href="/blog/backend/01-database/kv-document-capacity-planning/" data-link-title="1.10 KV / Document DB 容量規劃" data-link-desc="DynamoDB / Cosmos DB / Bigtable / MongoDB 等 KV / Document DB 的容量設計、partition key 取捨、capacity mode 選擇">1.10 KV / Document DB 容量規劃</a></li>
<li>選型上層：<a href="/blog/backend/00-service-selection/delivery-mode-selection/" data-link-title="0.21 交付形態選型：從全託管到自建的光譜與邊界" data-link-desc="在進入資料庫、快取與部署選型之前、先判斷服務該用託管平台（Wix / Shopify / Google Sites）、辦公生態自動化（Apps Script）、BaaS（Firebase）、半託管 CMS（WordPress）還是自建、並為日後遷往自建保留可遷出路徑">0.21 交付形態選型</a> / <a href="/blog/backend/00-service-selection/capability-buy-vs-build/" data-link-title="0.22 能力級買 vs 建：feature-as-a-service 與 BaaS bundle 選型" data-link-desc="在交付形態決定整個系統要不要自建之後、逐能力判斷該外包還是自建：辨識 managed 基礎設施、feature SaaS 與 BaaS bundle 三種外包深度、no-code 到 dev-tool 的服務光譜、買 vs 建判準與權重浮動、整合接縫與遷出代價">0.22 能力級買 vs 建</a> / <a href="/blog/backend/knowledge-cards/baas/" data-link-title="BaaS（Backend as a Service）" data-link-desc="說明把認證、資料庫、檔案儲存、推播打包成現成模組、由前端 SDK 直連的後端交付形態">BaaS 知識卡</a></li>
<li>從託管平台遷出的資產線盤點：<a href="/blog/backend/10-system-evolution/managed-platform-exit/" data-link-title="10.3 託管形態遷出：資產線盤點與並行期執行" data-link-desc="0.21 升級自建 tripwire 觸發後的執行劇本 — 把遷出拆成資料、身分、流量、整合各自的可攜性與斷點、設計舊平台與新系統的並行期與回切窗口、用部分遷出作為中繼形態">10.3 託管形態遷出</a></li>
<li>官方：<a href="https://firebase.google.com/docs/firestore">Firestore documentation</a>、<a href="https://firebase.google.com/docs/firestore/best-practices">Firestore best practices</a>、<a href="https://firebase.google.com/docs/firestore/pricing">Firestore pricing</a></li>
</ul>
]]></content:encoded></item></channel></rss>