NoSQL Databases: MongoDB, Cassandra, and Redis
NoSQL databases emerged to handle data that does not fit neatly into relational tables — or when relational databases cannot scale to meet modern application demands. The term “NoSQL” encompasses a diverse family of database technologies, each optimized for specific data models and access patterns.
This guide covers the major NoSQL categories, popular implementations, and guidance for choosing the right database for your use case.
Why NoSQL?
Relational databases excel at consistency, joins, and complex transactions. But they struggle with:
- Horizontal scaling — sharding a relational database is complex
- Flexible schemas — adding columns requires migrations
- High-velocity data — millions of writes per second
- Unstructured data — JSON, geospatial, graphs
NoSQL databases relax some of the ACID constraints to achieve performance, scalability, or flexibility that relational databases cannot match.
The CAP Theorem
The CAP theorem states that a distributed database can only guarantee two of three properties at any time: Consistency (all nodes see the same data), Availability (every request receives a response), and Partition Tolerance (the system continues despite network failures). NoSQL databases make explicit tradeoffs:
- CP databases (MongoDB, HBase) — choose consistency over availability during partitions
- AP databases (Cassandra, DynamoDB) — choose availability over consistency during partitions
- CA databases (relational databases) — choose consistency and availability, but cannot survive network partitions in distributed mode
Understanding these tradeoffs is essential for choosing the right NoSQL database for your application’s reliability requirements.
Categories of NoSQL Databases
1. Document Stores (MongoDB, Couchbase)
Document databases store data as JSON, BSON, or XML documents. Each document is self-contained, and documents in the same collection can have different structures.
// MongoDB document example
db.users.insertOne({
name: "Alice Smith",
email: "alice@example.com",
address: {
city: "San Francisco",
state: "CA"
},
roles: ["admin", "editor"],
created_at: new Date()
---);
// Query by field
db.users.find({ "address.city": "San Francisco" });
// Aggregation pipeline
db.orders.aggregate([
{ $match: { status: "completed" } },
{ $group: { _id: "$customer_id", total: { $sum: "$amount" } } },
{ $sort: { total: -1 } },
{ $limit: 10 }
]);Best for: Content management, e-commerce catalogs, real-time analytics, applications with evolving schemas.
2. Key-Value Stores (Redis, DynamoDB, Riak)
The simplest NoSQL model — every item is a key-value pair. The key is a unique identifier, and the value can be a string, JSON, binary data, or a more complex structure (dependent on the implementation).
// Redis examples
SET session:user123 "alice" EX 3600
GET session:user123
=> "alice"
// Redis data structures
LPUSH queue:tasks "process_report"
RPUSH queue:tasks "send_email"
LPOP queue:tasks
=> "process_report"
// Redis with Node.js client
const redis = require('redis');
const client = redis.createClient();
await client.set('user:42', JSON.stringify({ name: 'Alice', score: 100 }));
const user = JSON.parse(await client.get('user:42'));Redis runs entirely in memory, making it extremely fast — sub-millisecond response times. It supports data structures like strings, hashes, lists, sets, sorted sets, and streams.
Best for: Caching, session management, real-time leaderboards, message queues, rate limiting.
3. Column-Family Stores (Cassandra, HBase, Scylla)
Column-family databases store data in rows and columns, but unlike relational databases, each row can have different columns. They are designed for massive scale across many commodity servers.
-- Cassandra Query Language (CQL) — looks like SQL
CREATE TABLE sensor_data (
sensor_id UUID,
timestamp TIMESTAMP,
temperature FLOAT,
humidity FLOAT,
location TEXT,
PRIMARY KEY (sensor_id, timestamp)
) WITH CLUSTERING ORDER BY (timestamp DESC);
-- Insert
INSERT INTO sensor_data (sensor_id, timestamp, temperature, humidity, location)
VALUES (uuid(), toTimestamp(now()), 22.5, 60, 'rack-1');
-- Query by partition key
SELECT * FROM sensor_data WHERE sensor_id = ?;Cassandra offers tunable consistency — you can choose between strong consistency (read from all replicas) and eventual consistency (read from one replica). It has no single point of failure and supports multi-datacenter replication natively.
Best for: Time-series data, IoT sensor data, recommendation engines, messaging systems, applications requiring high write throughput.
4. Graph Databases (Neo4j, Amazon Neptune, ArangoDB)
Graph databases model data as nodes (entities), edges (relationships), and properties. They excel at traversing relationships efficiently.
// Neo4j Cypher queries
CREATE (alice:Person {name: "Alice"})
CREATE (bob:Person {name: "Bob"})
CREATE (alice)-[:KNOWS {since: 2020}]->(bob)
CREATE (alice)-[:WORKS_AT]->(company:Company {name: "Acme"})
// Find friends of friends
MATCH (alice:Person {name: "Alice"})-[:KNOWS]->(friend)-[:KNOWS]->(friend_of_friend)
RETURN friend_of_friend.name
// Shortest path
MATCH path = shortestPath(
(alice:Person {name: "Alice"})-[:KNOWS*]-(david:Person {name: "David"})
)
RETURN pathGraph databases make relationship-heavy queries thousands of times faster than relational JOINs.
Best for: Social networks, recommendation engines, fraud detection, knowledge graphs, network management.
Consistency Models
Different NoSQL databases offer different consistency guarantees:
Eventual consistency — after a write, all replicas will eventually converge. Reads may return stale data for a short window. This is the default for Cassandra, DynamoDB, and Riak. It provides the highest availability and lowest latency.
Strong consistency — after a write, all subsequent reads return the latest data. MongoDB with writeConcern: "majority" and readConcern: "majority" provides strong consistency. It ensures the application always sees the latest state but adds latency.
Read-your-writes consistency — a client always sees its own writes, but other clients may see stale data. This is a common compromise for session stores and user profiles.
Monotonic reads — a client never sees a previous version of data after seeing a newer version. This prevents the confusing “time travel” phenomenon in distributed systems.
Choosing the Right NoSQL Database
| Use Case | Recommended | Why |
|---|---|---|
| Flexible schemas, JSON data | MongoDB | Rich query language, mature ecosystem |
| High-speed caching | Redis | Sub-millisecond, in-memory |
| Write-heavy applications | Cassandra | Linear scalability, no single point of failure |
| Complex relationships | Neo4j | Native graph traversal, Cypher query language |
| Full-text search | Elasticsearch | Built on Lucene, powerful aggregations |
| Time-series data | InfluxDB or TimescaleDB | Optimized for timestamped data |
Polyglot Persistence
Modern applications rarely use a single database. A typical architecture might use:
- PostgreSQL for transactions and structured data
- Redis for caching and session management
- MongoDB for product catalogs and content
- Elasticsearch for search and analytics
This approach, called polyglot persistence, lets you use the best tool for each job.
Migration Strategy
Moving from SQL to NoSQL is rarely a simple migration. A practical approach:
- Identify the pain point — is it schema flexibility, read latency, write throughput, or scale?
- Start with a single bounded context — migrate one feature or service at a time (e.g., move product catalog to MongoDB while keeping orders in PostgreSQL)
- Dual-write during transition — write to both databases during migration, compare outputs, and validate correctness
- Cut over when confident — route reads to the new database only after validation
When to Stick with SQL
NoSQL is not always better. Choose a relational database when:
- Your data is highly structured and relationships are critical
- You need ACID transactions across multiple entities
- Your queries involve complex joins and aggregations
- You need strong consistency guarantees
- Your team is more familiar with SQL
Many teams start with PostgreSQL and add NoSQL databases only when specific requirements (scale, schema flexibility, specific data models) demand it.
Conclusion
NoSQL databases are powerful tools, but they are not replacements for relational databases — they are alternatives for specific use cases. Understand your data model, access patterns, and scalability requirements before choosing. In many cases, the right answer is a combination of SQL and NoSQL databases working together.
Related: Check our PostgreSQL vs MySQL guide.
FAQ
What does NoSQL stand for? “NoSQL” originally meant “No SQL” but is now commonly understood as “Not Only SQL.” It describes databases that use non-relational data models — document, key-value, column-family, graph — to address use cases where traditional SQL databases are inefficient.
Can NoSQL databases handle ACID transactions? Some can. MongoDB supports multi-document ACID transactions (since version 4.0). CockroachDB provides ACID across distributed nodes. However, most NoSQL databases relax ACID guarantees in favor of performance and scalability. Evaluate transaction requirements carefully before choosing.
How do I choose between MongoDB and Cassandra? MongoDB is ideal for flexible schemas, nested data, and applications needing a rich query language. Cassandra excels at high write throughput, multi-datacenter replication, and time-series data. If your workload is write-heavy and you can tolerate eventual consistency, Cassandra is strong. If you need complex queries and aggregation, choose MongoDB.
Is DynamoDB a NoSQL database? Yes, DynamoDB is a fully managed key-value and document database offered by AWS. It is based on the same design principles as Dynamo (the original Amazon paper that inspired many NoSQL databases). DynamoDB offers single-digit-millisecond latency, auto-scaling, and multi-region replication.
How does sharding work in NoSQL databases? Sharding distributes data across multiple servers. MongoDB uses range-based or hashed sharding with a config server managing metadata. Cassandra uses consistent hashing where each node owns a range of tokens. Redis Cluster uses hash slots (16384 total). The sharding approach affects rebalancing, query routing, and node addition/removal.
For a comprehensive overview, read our article on Acid Transactions Guide.