Data Engineering  /  Data Modeling

๐Ÿงฑ Data Modeling 20 guides ยท updated 2026

From ER diagrams to data mesh โ€” relational, dimensional, NoSQL, and governance-driven modeling for building data platforms people can trust.

NoSQL Data Modeling: Design from Queries, Not Entities

The most expensive mistake teams make with NoSQL is bringing relational habits with them. They create a โ€œtableโ€ per entity, sprinkle in references, and then discover โ€” usually in production โ€” that the database they chose for speed now needs twelve round-trips to render one screen. NoSQL databases are not โ€œschemaless relational databases.โ€ They reward a fundamentally different modeling process, and this post explains it.

Audience: engineers who know relational modeling and are designing for DynamoDB, MongoDB, Cassandra, Redis, or similar systems for the first time.

The Inversion: Relational Models Data, NoSQL Models Queries

Relational modeling works forward from the domain: identify entities, normalize, and trust the query optimizer to answer any question with joins. That flexibility is the relational modelโ€™s superpower โ€” and its cost, because joins across distributed machines are expensive, which is precisely why most NoSQL systems donโ€™t offer them (or offer them reluctantly).

NoSQL modeling works backwards from the access patterns:

  1. List every query and write the application will perform. Literally enumerate them: โ€œget user profile by ID,โ€ โ€œlist a userโ€™s 20 most recent orders,โ€ โ€œget all items in an order.โ€
  2. Estimate each patternโ€™s frequency and latency requirement.
  3. Design the data layout so that each important read is served by a single lookup โ€” one key fetch, one partition read, one document.
  4. Accept whatever duplication that layout requires, and plan how writes keep the copies consistent.

The mantra worth memorizing: relational databases optimize for storage and flexibility; NoSQL databases optimize for known access at scale. If your access patterns are genuinely unknown, that is an argument for a relational database, not against modeling.

The Central Trade: Embed vs. Reference

Every NoSQL design decision eventually reduces to one question โ€” when two pieces of data are related, do you embed one inside the other, or store them separately and reference?

Embed when data is accessed together and owned together. An order and its line items are read together, written together, and line items have no life outside their order. Embedding them in one document means one read serves the whole order screen:

{
"order_id": "ord_9812",
"customer_id": "cus_311",
"status": "shipped",
"items": [
{ "sku": "KB-45", "name": "Keyboard", "qty": 2, "price": 45.0 },
{ "sku": "MN-210", "name": "Monitor", "qty": 1, "price": 210.0 }
],
"shipping_address": { "city": "Pune", "pincode": "411001" }
}

Notice name and price are copied from the product catalog into the order. In relational thinking this is a violation; here itโ€™s correct twice over โ€” it makes the read self-contained, and it snapshots what the customer actually saw at purchase time.

Reference when data is shared, unbounded, or independently updated. The customer isnโ€™t embedded in the order, because customers exist across thousands of orders and their profile changes independently. Similarly, never embed unbounded lists โ€” a userโ€™s โ€œactivityโ€ array that grows forever will eventually hit document size limits (16 MB in MongoDB, 400 KB per item in DynamoDB) and slow every read of the parent.

Three questions decide it:

The Model Families and What Theyโ€™re Each Shaped For

โ€œNoSQLโ€ covers four genuinely different data models. Choosing among them is a modeling decision:

Key-value (Redis, DynamoDB in its simplest use). The model is a hash map: opaque value behind a key. Blazing and rigid โ€” you get exactly the lookups you designed keys for. The modeling skill is key design: session:{user_id}, cart:{user_id}. Perfect for sessions, caches, feature flags, counters.

Document (MongoDB, Firestore, Couchbase). Values become structured, queryable JSON with secondary indexes. The modeling skill is the embed/reference balance above, plus index design. The natural fit is aggregate-shaped data: orders, profiles, product listings โ€” anything a screen displays as one cohesive object. (The next post in this series goes deep on document design.)

Wide-column (Cassandra, HBase, ScyllaDB). Data is organized by a partition key (which machine holds it) and a clustering key (sort order within the partition). The modeling skill is designing partitions so each query reads exactly one, already sorted:

-- Cassandra: "recent readings per device" as a table designed for that query
CREATE TABLE readings_by_device (
device_id text,
reading_ts timestamp,
value double,
PRIMARY KEY ((device_id), reading_ts)
) WITH CLUSTERING ORDER BY (reading_ts DESC);

In Cassandra you create one table per query pattern and duplicate data across them at write time. Thatโ€™s not a workaround; it is the intended methodology.

Graph (Neo4j, Neptune). Relationships become first-class stored objects, ideal when the questions are about connections โ€” covered in its own post later in this series.

Handling Duplication Without Getting Burned

Denormalization is the price of single-read access, and itโ€™s payable โ€” but only with eyes open:

A Worked Miniature: Modeling a Simple E-Commerce App on DynamoDB

Access patterns: (1) get customer profile, (2) list customerโ€™s recent orders, (3) get one order with items, (4) get product details.

A common single-table design uses generic keys where several entity types share one table, laid out so each pattern is one query:

PKSKcontents
CUS#311PROFILEname, email
CUS#311ORD#2026-06-01#9812status, total (order summary)
ORD#9812ITEM#1 โ€ฆ ITEM#nembedded snapshot of each line
PRD#KB-45DETAILScatalog record

Pattern 2 becomes a single query โ€” PK = CUS#311, SK begins_with ORD# โ€” returning orders already sorted by date because the date is in the sort key. That trick, encoding sort order into keys, is the wide-column mindset applied inside DynamoDB, and itโ€™s the kind of design you simply cannot retrofit after launch. Model first.

When NoSQL Is the Wrong Answer

Honesty clause: reach for relational when access patterns are exploratory or ad hoc, when multi-entity transactions dominate (ledgers, inventory reservation), or when data volume is modest and always will be โ€” PostgreSQL at ordinary scale gives you flexibility, integrity, and joins for free. The strongest NoSQL designs come from teams who could articulate exactly why the relational model didnโ€™t fit this workload.

The takeaway: in NoSQL, the schema lives in your key design and your duplication strategy, and itโ€™s decided by the queries you enumerate before writing code. Skip that enumeration and you donโ€™t have a schemaless database โ€” you have an unmodeled one.