← Kỹ sư dữ liệu← Data Engineer
Kỹ sư dữ liệuData Engineer19 Th7, 2026Jul 19, 202626 phút đọc20 min read

Cơ sở dữ liệu NoSQLNoSQL Databases

Thuộc bộ kiến thức Data Engineer Roadmap.

Tổng quan

Cơ sở dữ liệu NoSQL xuất hiện khắp nơi trong công việc của data engineer, nhưng hiếm khi là đích đến cuối cùng. Chúng thường đóng một trong hai vai trò: hệ thống vận hành (operational) mà pipeline trích xuất dữ liệu ra, hoặc lớp serving tốc độ cao mà pipeline ghi kết quả vào. Các application engineer chọn một họ NoSQL vì nó phù hợp với access pattern mà service của họ cần (session cache, product catalog, social graph). Đến lượt data engineer phải xử lý hệ quả: làm sao lấy dữ liệu ra từ một store không có schema cố định và không có JOIN, và làm sao đẩy kết quả đã xử lý ngược vào một store phải trả lời trong vài mili-giây.

Note này giả định người đọc đã nắm nền tảng khái niệm từ Backend — Cơ sở dữ liệu NoSQL — CAP theorem, bốn họ NoSQL, và data modeling cơ bản. Hãy đọc bài đó trước nếu các thuật ngữ như “eventual consistency” hay “partition tolerance” còn xa lạ. Ở đây, trọng tâm chuyển sang các góc nhìn đặc thù của data engineering: NoSQL như một nguồn (source) để ingest (xem Nguồn dữ liệu & Ingestion), NoSQL như một lớp serving sau khi xử lý analytics hoặc ML, và các engine mà roadmap này nhắc riêng — Bigtable, CosmosDB, Neptune — mà bài backend không đi sâu.

Kiến thức nền tảng

Bốn họ NoSQL, tóm tắt nhanh

HọMô hìnhEngine ví dụThế mạnh điển hình
Key-valueValue không định dạng đứng sau một keyRedis, Memcached, DynamoDBLookup dưới mili-giây, caching, session state
DocumentDocument JSON/BSON bán cấu trúcMongoDB, CouchDBLinh hoạt, lồng nhau, dễ tiến hóa
Wide-columnHàng thưa (sparse) được khóa bởi partition key + clustering keyCassandra, HBase, BigtableGhi thông lượng cao, time-series, dữ liệu khổng lồ
GraphNode và edge là công dân hạng nhấtNeo4j, Amazon NeptuneTraversal, truy vấn nặng về quan hệ

Định nghĩa đầy đủ, các đánh đổi của CAP theorem, và hướng dẫn data modeling tổng quát cho từng họ nằm ở Backend — Cơ sở dữ liệu NoSQL. Nội dung dưới đây xây dựng tiếp trên nền đó thay vì lặp lại.

Hai chiều luân chuyển dữ liệu

Một cơ sở dữ liệu quan hệ OLTP là “nguồn” kinh điển mà data engineer trích xuất, nhưng một phần rất lớn dữ liệu ứng dụng hiện đại lại nằm trong các NoSQL store — một app mobile chạy trên MongoDB, một giỏ hàng thương mại điện tử trong DynamoDB, một đội IoT ghi liên tục vào Cassandra. Vì vậy công việc data engineering xoay quanh NoSQL chia thành hai mối quan tâm khác biệt, kéo theo hai hướng ngược nhau:

  1. Chiều ingestion (NoSQL là source): trích xuất dữ liệu vận hành ra khỏi NoSQL store, làm phẳng và chuẩn hóa nó, rồi nạp vào warehouse hoặc lake để phân tích. Thách thức ở đây là schema-on-read: nguồn không có cấu trúc bắt buộc, nên engineer phải tự áp đặt cấu trúc.
  2. Chiều serving (NoSQL là sink): lấy kết quả đầu ra của một batch job, streaming pipeline, hay mô hình ML — số liệu tổng hợp, feature, gợi ý, điểm số — rồi ghi vào một NoSQL store để ứng dụng đọc lại trong vài mili-giây. Thách thức ở đây là thiết kế access pattern và key cho một hệ thống sẽ không bao giờ nhận một truy vấn ad-hoc nào nữa.

Cả hai chiều đều quan trọng, và việc gộp lẫn chúng là lỗi thường gặp: các quyết định modeling giúp một store trở thành source tốt (document lồng nhau phong phú, schema rộng và linh hoạt) thường ngược lại với những gì làm nên một lớp serving tốt (denormalize, tra cứu bằng một key duy nhất, đã join sẵn).

Khái niệm chính

NoSQL như một source: trích xuất từ store schema-on-read

Nguồn quan hệ trao cho data engineer một hợp đồng ổn định: một tập cột và kiểu dữ liệu cố định được ép buộc tại thời điểm ghi (schema-on-write). Document store và wide-column store không có cam kết đó. MongoDB sẵn sàng để một collection orders chứa các document khác hình dạng nhau giữa các bản ghi, mảng lồng nhau có độ sâu khác nhau, và một field mà kiểu dữ liệu thay đổi theo thời gian (field discount từng là số, giờ là object {type, value}). Đây là schema-on-read: cấu trúc được phát hiện — hoặc áp đặt — tại thời điểm đọc, không phải tại thời điểm ghi.

Với data engineer, điều này tạo ra một tập vấn đề lặp lại khi trích xuất vào warehouse:

Các chiến lược làm phẳng phổ biến, xếp theo mức độ cấu trúc tăng dần:

Chiến lượcCách làmKhi nào dùng
Land raw JSONLưu mỗi document nguyên trạng vào một cột VARIANT/JSON, mỗi hàng một documentGiữ độ trung thực dữ liệu; hoãn việc modeling; landing zone tốt trong lake
Shred thành bảng conNổ (explode) mảng lồng nhau thành các bảng riêng, kèm khóa ngoại về bảng chaMảng lồng sâu, cardinality cao (order line items, event log)
Flatten thành bảng rộngĐưa các field cấp cao/lồng một cấp đã biết lên thành cột; giữ field hiếm/biến động trong một cột JSON còn lạiDocument có phần “core” khá ổn định cộng thêm đuôi dài field tùy chọn
Kiểu bán cấu trúc nativeGiữ cấu trúc lồng nhau dưới dạng cột STRUCT/ARRAY native, truy vấn được bằng cú pháp dot/arrayWarehouse cloud hiện đại (BigQuery, Snowflake, Redshift Spectrum) hỗ trợ sẵn

Trong thực tế, cách tiếp cận hai giai đoạn hoạt động tốt: land document thô không đổi (audit trail, khả năng replay, lưới an toàn cho schema evolution), sau đó áp một tầng transform — thường là dbt hoặc Spark job — để flatten thành hình dạng mà analyst thực sự truy vấn. Schema drift nên được phát hiện, không nên âm thầm hấp thụ: cảnh báo khi xuất hiện một nhóm field mới hoặc một field đã biết đổi kiểu, để logic flatten được cập nhật một cách có chủ đích.

Cơ chế trích xuất cũng khác nhau đáng kể theo từng engine:

NoSQL như một lớp serving: chiều luân chuyển ngược

Sau khi một pipeline tính ra thứ gì đó có giá trị — một danh sách gợi ý, điểm gian lận (fraud score), ước tính giá trị vòng đời khách hàng, một feature vector đã tính sẵn — kết quả đó thường cần đến tay ứng dụng trong vài mili-giây, với concurrency cao, được khóa bởi một ID đơn giản. Warehouse là công cụ sai cho việc này: nó được tối ưu cho truy vấn phân tích quét nhiều dữ liệu (scan-heavy), không phải tra cứu một hàng đơn lẻ ở độ trễ mức request. Đây là lúc chiều serving của NoSQL vào cuộc, và đây thực sự là một bài toán kỹ thuật khác với ingestion.

Các pattern điển hình:

Thiết kế cho chiều serving đảo ngược bản năng data-modeling thông thường: thay vì normalize để linh hoạt, engineer denormalize mạnh tay và thiết kế key schema xoay quanh một access pattern duy nhất mà ứng dụng cần — thường là “lấy mọi thứ cần để render màn hình/response này cho ID này trong một request”. Thiết kế đúng key ở đây cũng chính là kỷ luật thiết kế partition key trong Cassandra (xem bên dưới), chỉ áp dụng cho một store khác.

Cassandra và wide-column store, đi sâu

Cassandra (và wide-column store nói chung) là lựa chọn mặc định trong data engineering bất cứ khi nào workload nặng về ghi, chủ yếu append, và có thứ tự tự nhiên theo thời gian hoặc sự kiện — telemetry, dữ liệu cảm biến, sự kiện ứng dụng, lịch sử tin nhắn. Lý do bắt nguồn trực tiếp từ storage engine: cấu trúc lưu trữ log-structured merge-tree (LSM) của Cassandra làm cho việc ghi rẻ (append vào commit log và memtable trong bộ nhớ, sau đó flush ra SSTable bất biến), và kiến trúc masterless, dạng ring với replication có thể điều chỉnh cho phép việc ghi rơi vào bất kỳ node nào mà không cần một coordinator nghẽn cổ chai duy nhất — thông lượng tăng gần như tuyến tính khi thêm node.

Thiết kế partition key là quyết định quan trọng nhất trong một data model của Cassandra, và đáng để đi sâu vì nó quyết định cả hiệu năng truy vấn lẫn mức độ phân bổ đồng đều của dữ liệu trên cluster:

Mô hình consistency của Cassandra là nửa còn lại của đánh đổi mà data engineer phải tính đến. Mỗi thao tác đọc và ghi chỉ định một consistency level (ONE, QUORUM, ALL, v.v.) độc lập với nhau, và Cassandra mặc định là eventual consistency: một ghi được xác nhận ở ONE có thể chưa hiển thị cho một đọc ở ONE trên replica khác cho đến khi replication bắt kịp. Với pipeline data engineering, điều này có hệ quả cụ thể — các tiến trình CDC đọc từ Cassandra có thể thấy các ghi hơi lệch thứ tự giữa các partition, và các job trích xuất batch nên chấp nhận những khoảng độ trễ replication nhỏ thay vì giả định một snapshot nhất quán tức thời trên toàn cluster. Dùng QUORUM cho đọc/ghi siết chặt điều này với cái giá là độ trễ, và là lựa chọn phổ biến khi pipeline cần đảm bảo read-your-writes mạnh hơn.

Bigtable: engine wide-column của Google Cloud

Bigtable là wide-column store được quản lý hoàn toàn (fully managed) của Google Cloud, và nó có một vị trí đặc biệt trong lịch sử NoSQL: bài báo “Bigtable” gốc của Google năm 2006 là tổ tiên chung của cả HBase (một bản triển khai mã nguồn mở lại) và, gián tiếp, Cassandra (kết hợp data model của Bigtable với mô hình phân phối của Amazon Dynamo). Vì vậy Bigtable, HBase và Cassandra có nét họ hàng — lưu trữ thưa, được sắp xếp, hướng column-family, khóa theo row key — dù đặc tính vận hành khác nhau.

Thiết kế của Bigtable xoay quanh một row key được chọn kỹ, sắp xếp theo thứ tự từ điển (lexicographic), với mọi đọc/ghi cho một row key được định tuyến đến tablet server đang chịu trách nhiệm cho dải key đó. Điều này khiến thiết kế row key trở thành bài toán tương đương với partition key của Cassandra, cộng thêm một điểm khác biệt: vì row key được lưu theo thứ tự sắp xếp và chia thành các dải key liên tục (tablet) trên nhiều server, một key tăng đơn điệu (như một timestamp thô) khiến mọi ghi mới đều rơi vào cùng một tablet “nóng” ở cuối dải key. Cách khắc phục chuẩn là salt hoặc đảo ngược key — thêm tiền tố là giá trị hash hoặc đảo ngược, hoặc đặt một ID entity tự nhiên lên trước timestamp (ví dụ device123#reversed_timestamp) — để trải đều việc ghi trên các tablet.

Trong pipeline data engineering, Bigtable xuất hiện phổ biến nhất với vai trò:

MongoDB, đi sâu

Mô hình document của MongoDB tự nhiên phù hợp với phía “source” của phân chia ingestion/serving chính vì lý do product team yêu thích nó: nó ôm lấy dữ liệu bán cấu trúc, lồng nhau, tiến hóa liên tục. Một hồ sơ người dùng, một mục catalog sản phẩm, hay payload sự kiện có thể có thêm field tùy chọn mới qua từng release mà không cần migration — và đó chính xác là lý do MongoDB rất thường là store vận hành mà data engineer sau này phải trích xuất và chuẩn hóa về một schema warehouse cứng nhắc (xem phần schema-on-read ở trên).

Aggregation pipeline của MongoDB đáng để hiểu rõ, cụ thể vì đây là cơ chế ETL/transform tích hợp sẵn của chính MongoDB, và nó có thể giảm đáng kể khối lượng công việc mà pipeline downstream phải làm. Một aggregation pipeline là một chuỗi các stage — $match (lọc), $project (định hình lại/chọn field), $unwind (làm phẳng một mảng thành nhiều document), $group (tổng hợp), $lookup (một stage kiểu left-outer-join với collection khác), $sort, $out/$merge (ghi kết quả vào một collection) — nối tiếp nhau, về khái niệm tương tự một truy vấn SQL được xây từ các toán tử có thể kết hợp thay vì một câu lệnh khai báo duy nhất. Với data engineer, điều này có ý nghĩa theo hai cách:

Về mặt vận hành, MongoDB cực kỳ phổ biến làm datastore chính đằng sau các ứng dụng nặng về nội dung và catalog (CMS, catalog sản phẩm, hồ sơ người dùng, backend app mobile), khiến nó là một trong những NoSQL source được trích xuất thường xuyên nhất mà data engineer gặp trong thực tế — thường qua Change Streams cho CDC incremental hoặc dump full/incremental theo lịch cho nhu cầu báo cáo ít nhạy cảm về thời gian hơn.

Graph database: khi quan hệ chính là đối tượng phân tích

Phần lớn việc dùng NoSQL trong một pipeline coi quan hệ là một điều bất tiện cần làm phẳng đi. Graph database tồn tại cho trường hợp ngược lại: khi quan hệ giữa các entity chính là đối tượng phân tích, không phải cấu trúc phụ cần normalize bỏ đi. Các vòng gian lận (fraud ring), hệ thống gợi ý, phân tích mạng xã hội, ánh xạ phụ thuộc chuỗi cung ứng, và identity resolution (“đây có phải cùng một người trên năm tài khoản khác nhau không?”) đều chung một đặc điểm cấu trúc — câu trả lời thú vị nằm ở các đường đi (path) nhiều bước và mẫu kết nối, không nằm ở thuộc tính của bất kỳ hàng đơn lẻ nào.

Lý do thực tế để chọn Neo4j hoặc Amazon Neptune thay vì ép bài toán vào mô hình quan hệ hoặc document là hiệu năng ở độ sâu traversal. Một truy vấn quan hệ trả lời “bạn của bạn của bạn cũng theo dõi tài khoản X” đòi hỏi một chuỗi self-join mà chi phí tăng theo cấp số nhân với mỗi bước, và query planner suy giảm nghiêm trọng sau hai ba cấp. Một graph database lưu trực tiếp danh sách kề (adjacency) — mỗi node giữ con trỏ đến các edge của nó — nên đi sang bước kế tiếp là một phép theo con trỏ với thời gian không đổi, bất kể toàn bộ graph lớn cỡ nào. Điều này thường được tóm tắt là graph database biến quan hệ thành công dân hạng nhất thay vì giá trị được tính lúc truy vấn thông qua join.

Với data engineer, tín hiệu thực tế để chọn graph store là một ngưỡng cụ thể về hiệu năng và khả năng biểu đạt: một khi truy vấn “tìm các entity liên kết/liên quan” cần nhiều hơn hai ba join để diễn đạt, và đặc biệt khi cần số bước nhảy biến đổi hoặc không giới hạn (ví dụ “bất kỳ đường đi độ dài ≤ 6 nối hai tài khoản này”), graph database thường vượt trội cả về hiệu năng lẫn khả năng biểu đạt so với phương án quan hệ hay document.

CosmosDB: store đa mô hình của Azure

Azure Cosmos DB đi theo hướng khác so với các engine đơn mô hình ở trên: nó là một database đa mô hình (multi-model), phơi bày cùng một engine phân tán toàn cầu, partition theo chiều ngang bên dưới, thông qua nhiều API — Core (SQL) API cho workload document, một API tương thích MongoDB, một API tương thích Cassandra (wide-column), một Gremlin API (graph), và một Table API (key-value). Điểm hấp dẫn là một đội có thể chọn mô hình dữ liệu/API phù hợp với use case mà không cần cấp phát một sản phẩm database riêng, trong khi vẫn nhận được cùng các cam kết bên dưới: SLA độ trễ mức mili-giây một chữ số, các mức consistency có thể điều chỉnh (năm tùy chọn từ strong đến eventual), và replication toàn cầu tự động.

Trong một stack dữ liệu tập trung vào Azure, CosmosDB có xu hướng xuất hiện ở cả hai phía của sự phân chia được đề cập trong bài này: như một source vận hành (một ứng dụng xây trên SQL hoặc MongoDB API), được trích xuất qua Change Feed (tương đương Change Streams của MongoDB hay DynamoDB Streams) vào các pipeline Azure Synapse hoặc Data Factory; và như một lớp serving, nhận kết quả đã xử lý — gợi ý, giá trị feature, số liệu tổng hợp — từ pipeline Synapse/Databricks để ứng dụng tiêu thụ với độ trễ thấp, đúng vai trò mà DynamoDB hay Bigtable đảm nhận trong stack AWS/GCP. Điểm liên quan chính với một data engineer làm việc trên nhiều cloud là nhận ra rằng Change Feed và bề mặt đa API của CosmosDB cho phép nó thay thế cho nhiều engine kể trên, tùy vào API mà đội ứng dụng đã chọn.

Bảng so sánh: họ NoSQL, vai trò trong pipeline, và mối quan tâm modeling

HọVai trò điển hình trong pipelineEngine ví dụMối quan tâm modeling chính
Key-valueServing (tra cứu nhanh theo ID)DynamoDB, RedisThiết kế key sao cho một access pattern là một lần get đơn; tránh cần truy vấn phụ
DocumentSource (store vận hành để trích xuất); đôi khi serving qua đọc trực tiếp từ appMongoDB, CouchDB, CosmosDB (SQL API)Lên kế hoạch cho schema drift và cấu trúc lồng/lặp; dùng aggregation pipeline để định hình trước khi trích xuất
Wide-columnCả hai — source thông lượng cao cho sự kiện/telemetry, và serving cho tra cứu time-series/featureCassandra, HBase, BigtableThiết kế partition/row key quyết định cả hiệu năng truy vấn lẫn phân bổ tải trên cluster
GraphSource và serving cho phân tích lấy quan hệ làm trung tâm (gian lận, gợi ý, identity)Neo4j, Amazon NeptuneModel theo pattern traversal trước tiên; truy vấn nhiều bước là lý do duy nhất để chọn graph
Đa mô hìnhCả hai, tùy API được dùngAzure CosmosDBMối quan tâm modeling giống hệt API tương ứng (document/wide-column/graph/key-value) mà ứng dụng đã chọn

Best Practices

Tài liệu tham khảo

Part of the Data Engineer Roadmap knowledge base.

Overview

NoSQL databases show up everywhere in a data engineer’s world, but rarely as the final destination. They are usually one of two things: the operational system a pipeline extracts from, or the fast-serving layer a pipeline writes back into. Application engineers pick a NoSQL family because it fits an access pattern their service needs (a session cache, a product catalog, a social graph). Data engineers then have to deal with the consequences: how to pull data out of a store that has no fixed schema and no JOIN, and how to push processed results back into a store that must answer in single-digit milliseconds.

This note assumes the conceptual foundation from Backend — NoSQL Databases — the CAP theorem, the four families, and basic data modeling. Read that first if terms like “eventual consistency” or “partition tolerance” are unfamiliar. Here, the focus shifts to the data-engineering-specific angles: NoSQL as a source for ingestion (see Data Sources & Ingestion), NoSQL as a serving layer after analytics or ML processing, and the engines this roadmap calls out specifically — Bigtable, CosmosDB, and Neptune — that the backend note doesn’t dwell on.

Fundamentals

The four families, briefly

FamilyModelExample enginesTypical strength
Key-valueOpaque value behind a keyRedis, Memcached, DynamoDBSub-millisecond lookups, caching, session state
DocumentSemi-structured JSON/BSON documentsMongoDB, CouchDBFlexible, nested, evolving records
Wide-columnSparse rows keyed by partition + clustering keyCassandra, HBase, BigtableHigh-throughput writes, time-series, huge datasets
GraphNodes and edges as first-class citizensNeo4j, Amazon NeptuneTraversals, relationship-heavy queries

Full definitions, the CAP theorem trade-offs, and general data-modeling guidance for each family live in Backend — NoSQL Databases. What follows here builds on top of that foundation rather than repeating it.

Two directions of data flow

A relational OLTP database is the classic “source” a data engineer extracts from, but a huge share of modern application data lives in NoSQL stores instead — a mobile app backed by MongoDB, an e-commerce cart in DynamoDB, an IoT fleet writing into Cassandra. Data engineering work around NoSQL therefore splits into two distinct concerns that pull in opposite directions:

  1. Ingestion direction (NoSQL as source): extracting operational data out of a NoSQL store, flattening and conforming it, and loading it into a warehouse or lake for analytics. The challenge here is schema-on-read: the source has no enforced structure, so the engineer must impose one.
  2. Serving direction (NoSQL as sink): taking the output of a batch job, streaming pipeline, or ML model — aggregates, features, recommendations, scores — and writing it into a NoSQL store so an application can read it back in milliseconds. The challenge here is designing access patterns and keys for a system that will never see an ad-hoc query again.

Both directions matter, and conflating them is a common mistake: the modeling decisions that make a store a good source (rich embedded documents, wide flexible schemas) are often the opposite of what makes it a good serving layer (denormalized, single-key-lookup, pre-joined).

Key Concepts

NoSQL as a source: extracting from schema-on-read stores

Relational sources hand a data engineer a stable contract: a fixed set of columns and types enforced at write time (schema-on-write). NoSQL document and wide-column stores make no such promise. MongoDB will happily let one orders collection contain documents with different fields across records, nested arrays that vary in depth, and fields whose type changes over time (a discount field that used to be a number and is now an object with {type, value}). This is schema-on-read: structure is discovered — or imposed — at the moment of reading, not enforced at the moment of writing.

For a data engineer, this creates a recurring set of problems when extracting into a warehouse:

Common flattening strategies, roughly in order of increasing structure:

StrategyWhat it doesWhen to use
Land raw JSONStore each document as-is in a VARIANT/JSON column, one row per documentPreserve fidelity; defer modeling; good first landing zone in a lake
Shred to child tablesExplode nested arrays into separate tables with a foreign key back to the parentDeeply nested, high-cardinality arrays (order line items, event logs)
Flatten to wide tablePromote known top-level and one-level-nested fields to columns; keep rare/variable fields in a residual JSON columnDocuments with a mostly-stable “core” schema plus a long tail of optional fields
Semi-structured native typesKeep nested structures as native STRUCT/ARRAY columns queryable with dot/array syntaxModern cloud warehouses (BigQuery, Snowflake, Redshift Spectrum) that support this natively

In practice, a two-stage approach works well: land the raw document unchanged (audit trail, replay capability, schema evolution safety net), then apply a transformation layer — often dbt or a Spark job — that flattens into the shapes analysts actually query. Schema drift should be detected, not silently absorbed: alert when a new field family appears or a known field changes type, so the flattening logic can be updated deliberately.

Extraction mechanics also differ meaningfully by engine:

NoSQL as a serving layer: the reverse data flow

After a pipeline computes something valuable — a recommendation list, a fraud score, a customer lifetime-value estimate, a precomputed feature vector — that result usually needs to reach an application in milliseconds, at high concurrency, keyed by a simple ID. A warehouse is the wrong tool for that: it’s optimized for scan-heavy analytical queries, not single-row point lookups at request latency. This is where the serving direction of NoSQL comes in, and it is a genuinely different engineering problem from ingestion.

Typical patterns:

Designing for the serving direction inverts the usual data-modeling instinct: instead of normalizing for flexibility, the engineer denormalizes aggressively and designs the key schema around the one access pattern the application needs — usually “fetch everything needed to render this screen/response for this ID in one request.” Getting this key design right is the same discipline as partition-key design in Cassandra (see below), just applied to a different store.

Cassandra and wide-column stores in depth

Cassandra (and wide-column stores generally) are the default choice in data engineering whenever the workload is write-heavy, append-mostly, and naturally time-ordered or event-ordered — telemetry, sensor readings, application events, message history. The reasons trace directly to the storage engine: Cassandra’s log-structured merge-tree (LSM) storage makes writes cheap (append to a commit log and an in-memory memtable, flush to immutable SSTables later), and its masterless, ring-based architecture with tunable replication lets writes land on any node without a single bottleneck coordinator — throughput scales roughly linearly by adding nodes.

Partition key design is the single most important decision in a Cassandra data model, and it is worth dwelling on because it determines both query performance and how evenly data spreads across the cluster:

Cassandra’s consistency model is the other half of the trade-off data engineers must account for. Reads and writes each specify a consistency level (ONE, QUORUM, ALL, etc.) independent of each other, and Cassandra defaults to eventual consistency: a write acknowledged at ONE may not be visible to a read at ONE on a different replica until replication catches up. For data engineering pipelines this has concrete consequences — CDC processes reading from Cassandra may see writes slightly out of order across partitions, and batch extraction jobs should tolerate small windows of replication lag rather than assuming a snapshot is instantaneously consistent across the whole cluster. Using QUORUM reads/writes tightens this at the cost of latency, and is the common choice when a pipeline needs stronger read-your-writes guarantees.

Bigtable: Google Cloud’s wide-column engine

Bigtable is Google Cloud’s fully managed wide-column store, and it has a special place in NoSQL history: the original 2006 Google “Bigtable” paper is the common ancestor of both HBase (an open-source reimplementation) and, indirectly, Cassandra (which combined Bigtable’s data model with Amazon Dynamo’s distribution model). Bigtable, HBase, and Cassandra therefore share a family resemblance — sparse, sorted, column-family-oriented storage keyed by a row key — even though their operational characteristics differ.

Bigtable’s design centers on a single, carefully chosen row key, sorted lexicographically, with all reads/writes for a row key routed to the tablet server currently responsible for that key range. This makes row key design the Bigtable equivalent of Cassandra’s partition key problem, with one extra wrinkle: because row keys are stored in sorted order and split into contiguous key ranges (tablets) across servers, a monotonically increasing key (like a raw timestamp) causes all new writes to land on the same “hot” tablet at the end of the key space. The standard mitigation is to salt or reverse the key — prefixing with a hashed or reversed value, or leading with a natural entity ID before the timestamp (e.g. device123#reversed_timestamp) — to spread writes across tablets.

In data engineering pipelines, Bigtable shows up most often as:

MongoDB in depth

MongoDB’s document model is a natural fit for the “source” side of the ingestion/serving split precisely because product teams love it for the same reasons it’s painful to extract from: it embraces evolving, nested, semi-structured data. A user profile, a product catalog entry, or an event payload can gain new optional fields release after release without a migration — which is exactly why MongoDB is so often the operational store a data engineer later needs to extract from and conform into a rigid warehouse schema (see the schema-on-read discussion above).

MongoDB’s aggregation pipeline is worth understanding specifically because it is MongoDB’s own built-in ETL/transformation mechanism, and it can meaningfully reduce the work a downstream pipeline has to do. An aggregation pipeline is a sequence of stages — $match (filter), $project (reshape/select fields), $unwind (flatten an array into multiple documents), $group (aggregate), $lookup (a left-outer-join-like stage against another collection), $sort, $out/$merge (write results to a collection) — chained together, conceptually similar to a SQL query built from composable operators rather than a single declarative statement. For a data engineer, this matters in two ways:

Operationally, MongoDB is extremely common as the primary datastore behind content-heavy and catalog-heavy applications (CMSs, product catalogs, user profiles, mobile app backends), which makes it one of the most frequently extracted-from NoSQL sources data engineers encounter in practice — usually via Change Streams for incremental CDC or scheduled full/incremental dumps for less time-sensitive reporting needs.

Graph databases: when relationships are the analysis

Most NoSQL usage in a data pipeline treats relationships as an inconvenience to flatten away. Graph databases exist for the opposite case: when the relationships between entities are themselves the object of analysis, not incidental structure to normalize out. Fraud rings, recommendation engines, social network analysis, supply-chain dependency mapping, and identity-resolution (“is this the same person across five different accounts?”) all share a structural signature — the interesting answers live in multi-hop paths and connectivity patterns, not in any single row’s attributes.

The practical reason to reach for Neo4j or Amazon Neptune instead of forcing the problem into a relational or document model is performance at traversal depth. A relational query answering “friends of friends of friends who also follow account X” requires a chain of self-joins whose cost grows multiplicatively with each hop, and query planners degrade badly past two or three levels. A graph database stores adjacency directly — each node holds pointers to its edges — so traversing to the next hop is a constant-time pointer-follow regardless of how large the overall graph is. This is often summarized as graph databases making relationships first-class citizens rather than values computed at query time via joins.

For a data engineer, the practical trigger for reaching for a graph store is a concrete performance and expressiveness ceiling: once a “find connected/related entities” query needs more than two or three joins to express, and especially once it needs a variable or unbounded number of hops (e.g. “any path of length ≤ 6 connecting these two accounts”), a graph database usually outperforms and out-expresses the relational or document alternative by a wide margin.

CosmosDB: Azure’s multi-model store

Azure Cosmos DB takes a different approach from the single-model engines above: it is a multi-model database, exposing the same underlying globally distributed, horizontally partitioned engine through multiple APIs — the Core (SQL) API for document workloads, a MongoDB-compatible API, a Cassandra-compatible API (wide-column), a Gremlin API (graph), and a Table API (key-value). The pitch is that a team can pick the data model/API that fits the use case without provisioning a separate database product, while getting the same underlying guarantees: single-digit-millisecond latency SLAs, tunable consistency levels (five options from strong to eventual), and automatic global replication.

In an Azure-centric data stack, CosmosDB tends to appear on both sides of the split covered in this note: as an operational source (an application built on the SQL or MongoDB API), extracted via its Change Feed (CosmosDB’s equivalent of MongoDB Change Streams or DynamoDB Streams) into Azure Synapse or Data Factory pipelines; and as a serving layer, receiving processed results — recommendations, feature values, aggregates — from Synapse/Databricks pipelines for low-latency application consumption, the same role DynamoDB or Bigtable plays in AWS/GCP stacks. Its main relevance for a data engineer working across multiple clouds is recognizing that CosmosDB’s Change Feed and multi-API surface let it substitute for several of the engines above depending on which API a given application team chose.

Comparison: NoSQL family, pipeline role, and modeling concerns

FamilyTypical pipeline roleExample engineKey data-modeling consideration
Key-valueServing (fast lookups by ID)DynamoDB, RedisDesign the key so the one access pattern is a single get; avoid needing secondary queries
DocumentSource (operational store to extract from); occasional serving via app-facing readsMongoDB, CouchDB, CosmosDB (SQL API)Plan for schema drift and nested/repeated structures; use aggregation pipeline to pre-shape before extraction
Wide-columnBoth — high-throughput source for events/telemetry, and serving for time-series/feature lookupsCassandra, HBase, BigtablePartition/row key design controls both query performance and cluster load distribution
GraphSource and serving for relationship-centric analysis (fraud, recs, identity)Neo4j, Amazon NeptuneModel the traversal pattern first; multi-hop queries are the reason to choose graph at all
Multi-modelBoth, depending on which API is usedAzure CosmosDBSame modeling concerns as whichever API (document/wide-column/graph/key-value) the application chose

Best Practices

References