Chapter 08 · Redis JSON and Document-Oriented Data
Index JSON Fields with Redis Search and Keep Schema Evolution Explicit
Index selected Redis JSON paths with Redis Search while keeping source documents, schema evolution, prefix scope, index cost, and security explicit.
Learning outcomes
AtlasMart can fetch a product efficiently when it already knows the Redis key. Product discovery is different: “find outdoor products under 150 AZN whose name contains trail” is a secondary-query problem. Redis Search can index selected JSON paths, but the index is a derived structure with explicit prefix scope and schema.
Create a small Search index over JSON with explicit PREFIX and JSONPath schema attributes.
Prove direct JSON storage and Search index visibility as distinct mechanisms.
Use FT.INFO and FT.SEARCH to observe indexed-document state.
Design schema evolution/backfill rather than assuming a new Search schema migrates stored JSON.
Account for indexing memory/write amplification, field type semantics, Cluster/topology, and ACL boundaries.
All Chapter 08 mandatory labs reuse the disposable Chapter 01
environment: Redis Open Source 8.10.1 from Docker
Official Image redis:8.10.1, container
atlasmart-redis-ch01, standalone topology, host
publication 127.0.0.1:6379, TLS disabled only
because traffic stays on loopback, default ACL user disabled,
named ACL users atlasmart-app and
academy-admin, logical database 0, AOF with
appendfsync everysec plus RDB snapshots,
persistent /data volume, and no explicit Redis
maxmemory limit or eviction policy. Redis 8
integrates JSON and Search capabilities in Redis Open Source,
so the pinned image is the mandatory free/local path; no
separate Redis Stack image or managed service is required. The
primary client is the redis-cli shipped in the
same image. Fixtures are bounded under
atlasmart:ch08:*.
1. Verify feature surface before relying on it
Redis 8 integrates JSON and Search, but production code should still verify its target server and client rather than infer capability from a course label.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin INFO serverdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO JSON.GETdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin COMMAND INFO FT.CREATE
In managed or compatibility services, available commands, limits, and syntax can differ. This course's mandatory path is the pinned Redis Open Source 8.10.1 image.
2. Create a deliberately narrow JSON index
An index has a name, source type, key prefix scope, and schema.
JSONPath expressions select stored values; aliases such as
name and price become query
attributes.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.DROPINDEX atlasmart-ch08-products-idxdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.CREATE atlasmart-ch08-products-idx ON JSON PREFIX 1 atlasmart:ch08:search:product: SCHEMA '$.name' AS name TEXT '$.category' AS category TAG '$.priceCents' AS price NUMERIC '$.schemaVersion' AS schemaVersion NUMERIC
If the first drop reports “unknown index,” that is harmless setup evidence. We intentionally index four useful fields—not every JSON property.
3. Existing and future matching documents enter index scope
With PREFIX, the index watches JSON documents whose
Redis keys match that prefix. Direct JSON keys outside the
prefix remain valid JSON but are not part of this index.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch08:search:product:1 atlasmart:ch08:search:product:2 atlasmart:ch08:outside:product:3docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:search:product:1 '$' '{"schemaVersion":1,"name":"Trail Backpack","category":"outdoor","priceCents":12990,"internalNote":"A"}'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:search:product:2 '$' '{"schemaVersion":1,"name":"City Backpack","category":"urban","priceCents":9990,"internalNote":"B"}'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:outside:product:3 '$' '{"schemaVersion":1,"name":"Trail Bottle","category":"outdoor","priceCents":2500}'
4. FT.INFO is index evidence, not source-of-truth validation
FT.INFO exposes schema and indexing statistics.
Fields and exact statistic names can evolve, so interpret the
target release rather than hard-coding every line into
monitoring.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.INFO atlasmart-ch08-products-idx
Look for index definition/prefix, attributes, indexed document counts, and memory-related statistics. The outside-prefix document should not increase the indexed document count for this index.
5. Query only indexed attributes
Search uses the index schema, not arbitrary inspection of every JSON member. A TEXT field is analyzed for full-text search; a TAG field is for exact categorical values; a NUMERIC field supports numeric ranges.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.SEARCH atlasmart-ch08-products-idx '@name:(backpack)'docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.SEARCH atlasmart-ch08-products-idx '@category:{outdoor}'docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.SEARCH atlasmart-ch08-products-idx '@price:[0 11000]'
The Search response can return the stored JSON document by default. Chapter 09 covers analysis, escaping, dialects, sorting, pagination, aggregation, and profiling in depth.
6. JSON TAG semantics differ from Hash defaults
For JSON, a single string containing commas is not automatically treated like multiple Hash TAG values. Prefer JSON arrays when a field naturally has multiple categorical values, and index the array path intentionally.
| Stored form | Index design | Reasoning |
|---|---|---|
"outdoor,travel" string |
explicit separator if truly delimited | otherwise one TAG value |
["outdoor","travel"] array |
index JSON array/wildcard as TAG | preserves structured multi-value meaning |
7. Wrong approach: index every field “just in case”
Every indexed field adds schema complexity and can add index memory and write work. Indexing debug notes, volatile blobs, and fields never used in queries wastes resources and increases migration surface.
Start from concrete query requirements. Index only fields needed for filtering, text search, sorting, aggregation, or retrieval performance, then measure index memory, write latency, and query quality.
8. Search schema does not migrate source documents
Suppose v2 moves priceCents to
pricing.amountCents. Changing or replacing the
Search schema does not rewrite old v1 JSON documents. During
migration you may need readers/indexes that understand both
shapes, a backfill, and explicit cutover criteria.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:search:product:2 '$.pricing' '{"amountCents":9990,"currency":"AZN"}'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:search:product:2 '$.schemaVersion' '2'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.GET atlasmart:ch08:search:product:2 '$.priceCents' '$.pricing.amountCents' '$.schemaVersion'
The existing index still points at $.priceCents.
The new field is merely stored data until the Search schema
includes it.
9. Index visibility should be observed, not assumed identical to direct key access
After a JSON write, direct JSON.GET addresses
source data. Search queries address the maintained index. Treat
indexing as a separate visibility/capacity concern and verify
the semantics of the exact release/topology/service when
correctness depends on immediate query visibility.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:search:product:1 '$.category' '"clearance"'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.GET atlasmart:ch08:search:product:1 '$.category'docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.SEARCH atlasmart-ch08-products-idx '@category:{clearance}'
This is an observation exercise. Do not generalize one local run into a universal distributed visibility guarantee for every managed or clustered topology.
10. Memory: source document plus derived index
Search does not replace JSON storage; it adds a derived structure. Measure both.
docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch08:search:product:1docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app MEMORY USAGE atlasmart:ch08:search:product:2docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.INFO atlasmart-ch08-products-idx
FT.INFO provides index statistics appropriate to
the release. Record document count, index memory, write rate,
and query latency with production-like cardinality before
capacity planning.
11. ACLs and Search administration are separate concerns
The lab uses academy-admin for
FT.CREATE/FT.INFO because index
administration should not be granted casually to the
application. Production ACL design should distinguish document
reads/writes, Search queries, index-management commands, key
patterns, and network/TLS controls.
12. Cluster and multi-tenant boundaries
In Redis Cluster, JSON keys are partitioned by Redis key hash slot, while Search has topology-aware behavior that should be verified for your exact deployment. A JSON key prefix or Search prefix is not tenant authorization. Do not make one shared index across tenants simply because a prefix is convenient unless application and ACL isolation are designed explicitly.
13. Reproducible Search integration lab
Create a temporary index and two documents, query them, inspect state, then remove only the lab index/documents.
docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.DROPINDEX atlasmart-ch08-lab-idxdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.CREATE atlasmart-ch08-lab-idx ON JSON PREFIX 1 atlasmart:ch08:lesson4: SCHEMA '$.name' AS name TEXT '$.kind' AS kind TAG '$.price' AS price NUMERICdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:lesson4:1 '$' '{"name":"Trail Mug","kind":"outdoor","price":2200}'docker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app JSON.SET atlasmart:ch08:lesson4:2 '$' '{"name":"Office Mug","kind":"office","price":1800}'docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.SEARCH atlasmart-ch08-lab-idx '@kind:{outdoor}'docker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.INFO atlasmart-ch08-lab-idxdocker exec -e REDISCLI_AUTH=AtlasMart-Admin-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user academy-admin FT.DROPINDEX atlasmart-ch08-lab-idxdocker exec -e REDISCLI_AUTH=AtlasMart-App-Lab-Only-2026 atlasmart-redis-ch01 redis-cli --user atlasmart-app DEL atlasmart:ch08:lesson4:1 atlasmart:ch08:lesson4:2
If the initial drop says the index is missing, continue. Acceptance criteria before cleanup: the outdoor query returns only Trail Mug and FT.INFO reports the intended JSON prefix/schema.
14. Production judgment
Index JSON only when the query workload justifies a secondary structure. Bound prefix scope, choose field types from semantics, measure index memory/write amplification, test mixed schema versions, secure admin commands, and define rebuild/backfill/rollback. Direct key access remains simpler and cheaper when the application already knows the key.
15. Summary and bridge to Chapter 09
You now know how JSON storage and Search indexing compose without conflating them. Chapter 09 focuses entirely on Search schemas, TEXT/TAG/NUMERIC/GEO behavior, query syntax, aggregation, profiling, and index operations.
Check your understanding
- Does JSON.SET automatically make a field queryable by FT.SEARCH?
- What does PREFIX control?
- Why not index every JSON field?
- If v2 moves priceCents to pricing.amountCents, does the old Search schema migrate source docs?
- Why does the lab use academy-admin for index management?
Review the answers
No. An explicit Search index/schema is required.
Which Redis keys are in the index source scope.
Indexes consume memory/write work and enlarge schema/migration surface.
No. Source-document migration and Search-schema migration are separate operations.
To preserve least privilege: application JSON access and Search/index administration are different capabilities.
Authoritative references
- Redis JSON data type — JSON storage, typed operations, and command overview
- JSONPath syntax — modern dollar-path selection, wildcards, filters, slices, and recursive descent
- JSON.SET — root/path writes plus NX/XX and path-creation rules
- JSON.GET — serialized return shapes for modern and legacy paths
- JSON.TYPE — type introspection and modern/legacy return behavior
- JSON.OBJKEYS — object-key introspection and complexity
- JSON.ARRLEN — array length and multi-match behavior
- JSON.NUMINCRBY — atomic numeric path mutation
- JSON.STRAPPEND — atomic string append and resulting lengths
- JSON.ARRAPPEND — array append and resulting lengths
- JSON.MERGE — RFC 7396 merge-patch behavior for objects and arrays
- Index JSON documents — FT.CREATE ON JSON, JSONPath schema attributes, and indexing behavior
- FT.CREATE — Search index schema, prefix scope, and field types
- FT.INFO — index metadata and observable indexing state
- MEMORY USAGE — per-key memory evidence and sampling
- Redis 8.10 release notes — pinned server release family
- Schema definition — Search schema and JSONPath attributes
- Field and type options — TEXT/TAG/NUMERIC indexing semantics and cost choices
- FT.SEARCH — query execution and result shapes