15.1 Choosing a NoSQL Data Model Based on Access Patterns
Relational and NoSQL systems cover different data models and access patterns. NoSQL is a historical label for systems as different as key-value stores, document databases, wide-column stores, and graph databases. Compare concrete access paths and consistency boundaries before choosing a product.
First, Ask Whether Relational Databases Are Really Insufficient
Before switching databases, confirm which layer of the problem you're dealing with:
- Is query slowness due to missing indexes, outdated statistics, or poorly written SQL?
- Is write-hotspot behavior caused by inadequate partitioning, batch processing, or a flawed key design?
- Are frequent JSON field changes pushing the limits of relational databases’ JSON type support and online DDL capabilities?
- Is graph traversal the core workload, or is it just a rare recursive query?
- Do you need global multi-region availability, or is local high availability with read replicas sufficient?
Modern relational databases also support partitioning, replication, JSON fields, full-text indexing, and horizontal scaling. The value of NoSQL is rarely that "relational databases can't do it"; it is usually that a particular system has optimized a specific access pattern into a more direct interface and a more predictable, scalable unit.
Inferring the Data Model from Access Patterns
Before modeling, list the most frequent operations:
Operation Name Input Key Return Range Write Atomic Boundary
Read player profile player_id single aggregate single document
Read timeline user_id + time last 100 entries single partition
Find shortest path start_id, end_id multi-hop path multiple nodes/edges
Read configuration config_key single value single keyWithout knowing the starting keys for queries, the volume of records needed, or which fields must commit together, it's still too early to select a database.
Key-Value Model: Capabilities Focused on the Primary Key Path
Key-value storage converges its core interface onto key -> value. However, the claim that "values are opaque bytes" holds true only for certain products; Redis values are structured data that can be manipulated, and DynamoDB supports composite primary keys, secondary indexes, and document attributes.
Suitable use cases typically exhibit:
- Requests naturally carrying complete primary keys;
- The majority of operations occurring within a single key or clearly defined transaction scope;
- The ability to distribute hotspots through thoughtful key design;
- No reliance on ad-hoc filtering conditions that are dynamically added at runtime.
Key design directly influences data locality and load distribution. For example:
PK = tenant#42
SK = order#2026-08-03T10:15:00Z#9182This sketches a DynamoDB composite key. Supply PK equality and a suitable SK range. Timestamp strings must use one UTC format and precision for lexical ordering to match time ordering.
This design enables querying orders by tenant and time range, but if a particular tenant experiences high traffic, hotspots can still emerge. Hash distribution does not guarantee automatic uniformity of business load.
Document Model: Grouping Data That Is Read and Updated Together
Document databases store nested data using object or JSON/BSON-like structures. At the core of their design lies the decision between embedding and referencing:
- Subobjects that are read together, share a lifecycle, and have bounded quantities are well-suited for embedding;
- Independent, growing collections that are shared across multiple places or may expand indefinitely are better handled via references or table splitting;
- Document atomicity cannot protect business invariants that span data not included within the same document.
This JavaScript object illustrates a document shape without calling a MongoDB driver. The prices are illustrative; an application must define currency and units.
const order = {
_id: "order-9182",
customer_id: "customer-7",
status: "paid",
lines: [
{ sku: "product-1", quantity: 1, unit_price: 80 }
],
total: 80
};Here, order lines are embedded within the order document because they are read and live in sync with it. The embedded unit price preserves the price at purchase; it must not serve as the authoritative current product price.
"Flexible Schema" does not mean schema-less. Field meaning, types, version migrations, indexing, and validation still exist, though more responsibility is shifted to the application and deployment processes. Products like MongoDB offer schema validation and multi-document transactions, making the claim that "document databases lack constraints and transactions" obsolete.
Wide-Column Model: Precomputing Query Shapes Around Partition Keys
Cassandra's wide-column model is not "columnar storage" suitable for analytical databases. Instead, it distributes data by partition key, and within each partition, organizes rows according to clustering columns.
This is a Cassandra CQL 4.x/5.x schema fragment requiring a selected practice keyspace. It is not relational-database SQL.
CREATE TABLE events_by_device (
device_id text,
event_day date,
event_time timestamp,
event_id timeuuid,
payload text,
PRIMARY KEY ((device_id, event_day), event_time, event_id)
) WITH CLUSTERING ORDER BY (event_time DESC);This table is specifically designed to serve queries like "retrieve time-series events from a particular device on a given day." If you also need to query by alert type, you typically create a denormalized table tailored to that access pattern, rather than expecting arbitrary WHERE.
Partition keys must be bounded: only device_id could potentially accumulate years of events into a single massive partition, so we introduce event_day as a bucket. Cross-day reads require client-side or service-layer merging. A daily bucket is not a capacity guarantee: an assumed 1,000 events/s from one device still produces 86.4 million events/day. Use row width and the target partition size to decide whether to shorten the bucket or add a bounded shard component.
Graph Models: Relationships Are First-Class Data
Property graphs are typically composed of nodes, directed and typed relationships, and attributes attached to both nodes and relationships:
This Neo4j Cypher fragment requires User nodes, FOLLOWS relationships, and bound from/to parameters. User.id needs a uniqueness constraint or suitable index.
MATCH path = (a:User {id: $from})-[:FOLLOWS*1..4]->(b:User {id: $to})
RETURN path
LIMIT 1;This returns any matching path of 1–4 hops. LIMIT 1 neither guarantees the shortest path nor bounds traversal to a single visited node. For a shortest path, use the selected Cypher version's shortest-path syntax and inspect its plan. See Neo4j variable-length paths.
Graph databases excel in scenarios involving multi-hop traversal, path queries, connectivity analysis, and pattern matching, such as authorization inheritance, fraud networks, and knowledge graphs. If the business logic involves only a few layers of foreign-key relationships, traditional relational databases are often simpler and more straightforward.
Graph models still require constraints, indexes, and transactions; "no JOINs" does not mean no traversal cost. Highly connected super-nodes, unbounded paths, and incorrectly directed relationships can still lead to search explosions.
Selection Is Not a Product Ranking List
| Primary Requirement | Top Evaluation Focus | Key Risks |
|---|---|---|
| Strong constraints, frequent ad-hoc queries, cross-entity transactions | Relational database | Expansion boundaries, hot spots, and complex query management |
| Full primary key access, predictable low latency | Key-value systems | Key design, hot spots, secondary access paths |
| Read and write operations on aggregated objects with nested structures | Document databases | Unbounded document growth, consistency of duplicated data |
| Massive-scale, partition-ordered access | Wide-column systems | Query-driven modeling, tombstones, repair operations, and hot spots |
| Multi-hop relationships and path queries | Graph databases | Super nodes, traversal upper bounds, cluster scalability |
A single business can use multiple storage systems, but each additional system adds cost in terms of backups, monitoring, permissions, upgrades, change data capture (CDC), and failure handling. It's typically more reliable to start with a single authoritative database managing transactional facts, and then use caching, search, or graph projection services for specialized read models, rather than assigning a dedicated database to every data type.
Section Checkpoint
- Can infer key and data models from access patterns and atomic boundaries.
- Can distinguish between wide-column models and OLAP columnar storage.
- No longer generalizes all NoSQL systems as "schemaless, no transactions, cannot JOIN."
- Can describe the additional synchronization and operational overhead introduced by adding a second database.
References
The next section explores the fundamental failure conditions in distributed storage: what happens when a network partition occurs, does a read or write operation reject the request, wait for recovery, or return potentially stale results?