JavaScript Object Notation (JSON) has become the ubiquitous data format for web applications. Its flexibility, readability, and widespread tooling support have made it the first choice for transmitting data between web services.
As a popular in-memory data store, Redis plays a key role in many web architecture stacks. The ability to efficiently store, query, and manipulate JSON documents in Redis unlocks valuable use cases for powering real-time features.
In this comprehensive guide, we will explore the ins and outs of working with JSON in Redis, including:
- JSON storage and retrieval basics
- Advanced querying and manipulation with RedisJSON
- Best practices for indexing, data modeling, and caching
- When to reach for a JSON-specific database instead
Let‘s dive in!
JSON Storage Basics
The most straightforward way to store JSON in Redis is to treat it as a plain string value. For example:
SET user:1 ‘{"id":1,"name":"Alice"}‘
This approach works well enough for basic use cases. However, we quickly run into limitations:
- No native support for querying into JSON properties
- Manual serialization/deserialization is required
- No indexing for efficient lookups
- No validation checks on the JSON structure
Retrieving and updating whole JSON documents also becomes unwieldy:
GET user:1
// {"id":1,"name":"Alice"}
// Update name
SET user:1 ‘{"id":1,"name":"Alicia"}‘
As documents grow larger, rewriting the entire JSON string for small changes is incredibly inefficient.
There has to be a better way!
Introducing RedisJSON
RedisJSON is a Redis module that provides native support for storing, querying, and manipulating JSON documents. Let‘s look at some of the key features:
1. Transparent JSON Storage
RedisJSON handles all serialization/deserialization automatically. We can store documents without any stringification:
JSON.SET user:1 . ‘{"id":1,"name":"Alice"}‘
The . indicates where the JSON value begins. Retrieval automatically parses the JSON:
JSON.GET user:1
// {"id":1,"name":"Alice"}
Much cleaner!
2. JSON Path Queries
RedisJSON includes a JSONPath-like syntax for querying into documents:
JSON.GET user:1 .name
// "Alice"
This avoids manual manipulation of the raw JSON payload.
We can also query for nested properties:
JSON.GET user:1 .address.city
And return multiple matching results:
JSON.GET user:1 .phoneNumbers[*]
3. Atomic Counters
Incrementing counters inside JSON is accomplished via:
JSON.NUMINCRBY user:1 .logins 1
No more fetching, manipulating, and rewriting entire documents!
4. Indexing for Performance
As datasets grow large, scanning every JSON document on each query becomes prohibitive.
RedisJSON allows creating secondary indexes to accelerate queries:
// Index on user names
JSON.INDEX ADD user:*->name
// Now we can query efficiently even with millions of docs
JSON.GET user:*->name Alice
In short, RedisJSON brings the capabilities needed for production JSON use cases. It‘s like MongoDB but with the speed and versatility of Redis!
Advanced Querying and Manipulation
Now that we‘ve covered the basics of RedisJSON, let‘s dive deeper into advanced usage for unlocking more value:
Complex Query Conditions
We can filter documents by flexible conditions, not just simple equality:
// Name starts with A
JSON.GET user:*->name ^A*
// Published within last week
JSON.GET article:*->date [\d]{3}
Regular expressions, numeric ranges, nested logic – it‘s all supported for complex datasets.
Server-Side Aggregations
For analytical queries, RedisJSON supports aggregations directly inside Redis:
JSON.AGGREGATE article:* COUNT 1 AS num_articles
JSON.AGGREGATE article:* SUM .views AS total_views
This avoids transferring raw data to the client for processing.
Atomic Transactions
RedisJSON leverages Redis transactions for safe concurrent access:
JSON.TRANSACT
JSON.NUMINCRBY user:123 .logins 1
JSON.ARRAPPEND post:456 .views 123
EXEC
Now updates across multiple documents can be wrapped in transactions.
On-Demand Indexing
For rapidly changing data, indexes can be created and deleted programmatically:
JSON.INDEX DEL post:*->views
// Index when query load increases
JSON.INDEX ADD post:*->views
This balances dynamic datasets against query performance.
As you can see, RedisJSON provides a robust toolset beyond basic storage and retrieval!
Production Data Modeling
With great power comes great responsibility. To use RedisJSON effectively, we need robust data models.
Here are some key guidelines tailored for real-world systems:
Avoid Massive Documents
Redis deals with hot spots via partitioning – splitting keys evenly across nodes.
One huge JSON document funnels all load to a single node. Instead split across multiple keys:
JSON.SET user:123:profile {...}
JSON.SET user:123:settings {...}
100 small JSON documents scale better than one monster doc!
Embrace Specific Document Types
Treat objects with different access patterns as distinct document types for queries:
JSON.SET article:{id} ...
JSON.SET comment:{id} ...
Segregate types into separate key namespaces based on usage.
Index Strategically
Only index frequently filtered or sorted fields. Analyze slow queries to identify columns for indexing.
Use Redis SLOWLOG to find slow queries for diagnosis.
Benchmarking Indexing Performance
To demonstrate the power of RedisJSON‘s indexing, let‘s benchmark it!
First, we‘ll store a collection of documents without any secondary indexes:
for (var i = 0; i < 1000000; i++) {
JSON.SET doc:{i} . {
"title": "Document #" + i,
"content": "Lots of text...",
"created_date": "2023-02-28"
}
}
Now we‘ll benchmark different access patterns.
Query All Documents – 620 milliseconds
JSON.GET doc:{*}
No indexes means a full collection scan is required.
Query By Date Without Index – 3210 milliseconds
JSON.GET doc:*->created_date 2023-02-28
Add Index on Created Date
JSON.INDEX ADD doc:*->created_date
Now Query By Date – 38 milliseconds🌟
As you can see, the index powers over 80x faster date queries!
Applying this across clauses, filters, joins, etc unlocks order-of-magnitude speedups.
Comparing Database Options
While RedisJSON fills a useful niche, other database options excel for more advanced JSON use cases:
MongoDB shines with:
- Ad-hoc analytical queries
- Flexible compound indexes
- Aggregations and reporting
- Native search integration
Postgres is ideal for:
- Structured relational data
- Checking data integrity
- Complex server-side programming
Elasticsearch dominates in:
- Text search
- Geo-spatial queries
- Stream analytics
- Relevance-based ranking
Determine which strengths are most important before selecting a database.
Scaling JSON with Redis Cluster
As JSON collections grow large, Redis Cluster helps seamlessly scale capacity while keeping data safely redundant.
It automatically shards keys/documents across nodes in the cluster, routing requests in parallel. Adding more nodes linearly increases throughput and memory.
With RedisJSON, documents belonging to the same type should share a common key prefix for efficient partitioning in clusters. For example:
// Good
JSON.SET user:{id}:profile {...}
JSON.SET product:{id}:inventory {...}
// Avoid random keys
JSON.SET u:293847234 {...}
Smart key patterns activate clustering optimizations behind the scenes!
JSON Cache Optimization Tips
Caching slow remote resources as JSON is a killer app for RedisJSON. Here are some key optimization tips:
1. Set finite cache TTLs
Cache entries should eventually expire to prevent stale data. Choose reasonable TTLs per endpoint.
2. Refresh preemptively
Refresh cache entries BEFORE expiration to avoid poor efficiency during misses:
@hourly_cron
def update_cache():
data = fetch_remote()
json.set("data", ".", data)
3. Parallelize refreshes
Use a background queue to refresh multiple caches concurrently without blocking requests.
4. Cache by unique parameters
Index into caches by unique springs or identifiers instead of single monolithic entries.
This improves cache-hit ratios in dynamic apps.
Client Libraries to Access RedisJSON
While the Redis CLI enables direct database access, client libraries simplify connecting RedisJSON to applications:
| Language | Library |
|---|---|
| JavaScript | ioredis |
| Python | redis-py |
| Java | Jedis |
| Go | go-redis |
| C# | StackExchange.Redis |
These provide robust connectors from all major languages and frameworks. Under the hood, they handle:
- Connection pooling
- Serialization
- Optimized pipelines
- Handling failures
- Cluster awareness
Client libraries streamline access without needing direct socket commands.
When to Use a Dedicated JSON Database
As awesome as RedisJSON is, don‘t overstep its sweet spot. JSON-centric databases like MongoDB offer strengths around:
- Automatic indexing and query optimization
- Ad-hoc analytical queries
- Flexible structure validation checks
- Transactions with rollback
- Out-of-the-box replication, sharding
The rule of thumb – leverage Redis for speedy key/value access patterns rather than complex analytical queries. Use RedisJSON to accelerate apps, not emulate a full JSON document store!
Putting It All Together
JSON has become the "lingua franca" of web APIs and applications. Understanding how to effectively model, store, query, and cache JSON documents should be part of every developer‘s toolbox.
We explored RedisJSON for native JSON manipulation in Redis as well as guidelines for optimization. By following best practices around indexing, data modeling, scaling, libraries, and leveraging strengths – you will be building lightning fast systems to power your apps!


