The Six Families of NoSQL
NoSQL is not a single technology but a family of storage paradigms, each optimized for a different access pattern. Choosing the right one depends on how you query, not how you store.
Stores JSON/BSON documents with flexible schemas. Queries on nested fields. Examples: MongoDB, Couchbase.
Simple get/put by key. Extremely fast, often in-memory. Examples: Redis, Memcached, DynamoDB (simple mode).
Wide rows with dynamic columns grouped into families. Optimized for write-heavy, time-series-like workloads. Examples: Cassandra, HBase.
Nodes and edges as first-class citizens. Excels at traversals and relationship queries. Examples: Neo4j, Amazon Neptune.
Optimized for append-heavy, timestamp-indexed data with downsampling and retention policies. Examples: InfluxDB, TimescaleDB.
Full-text search over inverted indexes with scoring and aggregations. Examples: Elasticsearch, Apache Solr.
MongoDB: The Document Store
MongoDB stores data as BSON (Binary JSON) documents inside collections. There is no enforced schema at write time -- this is called schema-on-read. You decide how to interpret the data when you query it, not when you insert it.
BSON Document Structure
{
"_id": ObjectId("64a7f..."),
"name": "Alice",
"orders": [
{ "item": "Widget", "qty": 3, "price": 9.99 },
{ "item": "Gadget", "qty": 1, "price": 24.50 }
],
"address": { "city": "Bangalore", "zip": "560001" }
}
Aggregation Pipeline
MongoDB's aggregation pipeline is a sequence of stages that transform documents. Each stage feeds its output to the next, similar to Unix pipes.
Replica Sets & Sharding
Replica sets provide high availability: one primary node accepts writes, and secondary nodes replicate asynchronously. If the primary fails, an automatic election promotes a secondary.
Sharding distributes data across multiple machines by a shard key. Each shard holds a range (or hash) of keys. A mongos router directs queries to the correct shard.
Key-Value Powerhouses
Redis
Redis is an in-memory data structure store. Unlike simple key-value caches, Redis supports rich data structures: strings, lists, sets, sorted sets, hashes, streams, bitmaps, and HyperLogLogs.
| Data Structure | Use Case | Example Command |
|---|---|---|
| String | Caching, counters | SET key val, INCR key |
| Hash | Object storage | HSET user:1 name "Alice" |
| List | Queues, feeds | LPUSH queue task1 |
| Sorted Set | Leaderboards, ranking | ZADD board 100 "alice" |
| Stream | Event log, pub/sub | XADD stream * field val |
Persistence: Redis offers two persistence modes. RDB takes point-in-time snapshots at intervals. AOF (Append Only File) logs every write operation. You can combine both for durability with fast recovery.
Redis Cluster: Data is divided into 16,384 hash slots distributed across master nodes. Each master has replicas for failover. Clients use hash slot mapping to route commands directly to the right node.
DynamoDB
Amazon DynamoDB is a fully managed key-value and document database. Every table must have a partition key (hash key). Optionally, you add a sort key to enable range queries within a partition.
Global Secondary Indexes (GSI): A GSI lets you query on a completely different partition key and sort key than the base table. DynamoDB replicates data to the GSI asynchronously, so GSI reads are eventually consistent.
PK=USER#123, SK=ORDER#456) to avoid joins entirely.
Cassandra: Masterless Wide-Column Store
Apache Cassandra is designed for massive write throughput and linear horizontal scalability. Every node in the cluster is equal -- there is no single master or leader.
Gossip Protocol
Nodes communicate cluster state through a gossip protocol: each node periodically exchanges metadata (health, token ranges, schema versions) with a few random peers. Information propagates exponentially, reaching all nodes quickly.
Data Model
Cassandra tables have a partition key that determines which node stores the data, and optional clustering columns that determine sort order within a partition. Data within a single partition is stored together on disk for fast sequential reads.
CREATE TABLE orders (
customer_id UUID, -- partition key
order_date TIMESTAMP, -- clustering column
order_id UUID, -- clustering column
total DECIMAL,
PRIMARY KEY (customer_id, order_date, order_id)
) WITH CLUSTERING ORDER BY (order_date DESC);
Tunable Consistency
Cassandra lets you choose consistency per query. With a replication factor of 3:
| Consistency Level | Nodes Required | Trade-off |
|---|---|---|
ONE | 1 replica | Fastest, lowest consistency |
QUORUM | 2 of 3 replicas | Strong consistency if R+W > N |
ALL | 3 replicas | Strongest, but any node failure blocks writes |
LOCAL_QUORUM | Quorum in local DC | Multi-DC deployments, low latency |
R + W > N (reads + writes > replication factor), you get strong consistency. For example, QUORUM reads (2) + QUORUM writes (2) > 3 replicas = strong consistency.
Neo4j: The Graph Database
Neo4j stores data as a property graph: nodes (entities) connected by relationships (edges). Both nodes and relationships can hold key-value properties. Relationships are always directed and typed.
Cypher Query Language
Cypher uses ASCII-art syntax to describe graph patterns. Nodes are parentheses, relationships are arrows with brackets.
// Find friends of friends who bought the same product
MATCH (alice:Person {name: "Alice"})-[:FRIENDS_WITH]->(friend)
-[:FRIENDS_WITH]->(fof)-[:PURCHASED]->(product)
WHERE alice <> fof
RETURN fof.name, product.name;
Index-Free Adjacency
In Neo4j, each node physically stores pointers to its adjacent relationships. Traversing a relationship is a direct pointer follow, not a global index lookup. This means traversal cost is proportional to the local neighborhood size, not the total graph size -- a key advantage over relational JOIN-based graph queries.
ACID vs BASE, CAP & PACELC
ACID vs BASE
| Property | ACID (Relational) | BASE (NoSQL) |
|---|---|---|
| Atomicity / Basically Available | All-or-nothing transactions | System guarantees availability; partial failures are tolerated |
| Consistency / Soft state | DB moves from one valid state to another | State may change over time even without new input (replicas converging) |
| Isolation / Eventual consistency | Concurrent transactions don't interfere | Reads may see stale data temporarily, but will converge |
| Durability | Committed data survives crashes | (Still durable, but consistency is relaxed) |
CAP Theorem
In a distributed system experiencing a network Partition, you must choose between Consistency (every read returns the most recent write) and Availability (every request gets a response). You cannot have both during a partition.
PACELC
PACELC extends CAP: if there is a Partition, choose Availability or Consistency. Else (normal operation), choose Latency or Consistency.
| System | During Partition (PA/PC) | Else (EL/EC) |
|---|---|---|
| DynamoDB | PA (available) | EL (low latency) |
| Cassandra | PA (available) | EL (low latency) |
| MongoDB | PC (consistent) | EC (consistent) |
| HBase | PC (consistent) | EC (consistent) |
Time-Series & Search Engines
InfluxDB and TimescaleDB are optimized for time-stamped data. InfluxDB uses a custom TSM (Time-Structured Merge) storage engine with built-in downsampling and retention policies. TimescaleDB extends PostgreSQL with hypertables that auto-partition by time, giving you full SQL over time-series data.
Elasticsearch builds an inverted index: for each unique term, it stores a sorted list of document IDs containing that term. At query time, it scores documents using BM25 (Best Matching 25), a probabilistic relevance function that considers term frequency, inverse document frequency, and document length normalization.