Command Palette

Search for a command to run...

Hectal
PHASE 4Intermediate ~10 min· topic 5 of 6

Topic 4.5

JSON and the Query Engine: Documents with Indexes

In one line

Redis 8 stores native JSON documents you can read and update by path, and the Query Engine adds secondary indexes over hashes and JSON: full-text, numeric ranges, tags, geo, sorting and aggregations. It turns Redis from key-only lookup into a queryable, in-memory document store.

0/6 · 0%

Think of it like this

A library card catalogue. Books sit on shelves by ID (keys), but the catalogue lets you find them by author, subject or year without walking every shelf. The Query Engine is that catalogue, kept up to date every time a book is added or changed.

Key ideas

  1. 01

    JSON commands: JSON.SET key $ '{...}', JSON.GET key $.name $.price, JSON.MGET, JSON.NUMINCRBY key $.stock -1, JSON.ARRAPPEND, JSON.DEL key $.path, JSON.TYPE. Paths use JSONPath ($); updates change only the targeted part, atomically, without rewriting the whole document from the client.

  2. 02

    Indexes: FT.CREATE idx ON JSON|HASH PREFIX 1 product: SCHEMA ... declares fields as TEXT (full-text, stemming), TAG (exact values, like brand or status), NUMERIC (ranges, SORTABLE), GEO, and VECTOR (Topic 4.6). Every write to a key matching the prefix updates the index synchronously, so queries see your write immediately.

  3. 03

    Queries: FT.SEARCH idx "@brand:{acme} @price:[100 500] laptop" SORTBY price ASC LIMIT 0 10 RETURN 2 $.name $.price. Aggregations with FT.AGGREGATE ... GROUPBY 1 @brand REDUCE COUNT 0 AS n. Autocomplete with FT.SUGADD and FT.SUGGET.

  4. 04

    Costs: indexes use extra memory (often 20–100% of the indexed data), writes do more work, and big result sets are expensive. Keep indexes to fields you actually query; use TAG rather than TEXT for exact matches.

  5. 05

    Availability: built into Redis 8 Open Source; previously Redis Stack. On Valkey, JSON and search come from separate modules (valkey-json, valkey-search), and support in managed services varies, so check your provider. Clustered deployments need a query engine that coordinates across shards, so confirm your edition supports it before relying on it.

  6. 06

    When to use it: fast product filtering, session or entity lookup by attribute, autocomplete, real-time dashboards over hot data. When not: your source of truth needs joins, transactions across entities, or long-term storage, where PostgreSQL (or Elasticsearch/OpenSearch for large search workloads) fits better.

Code & diagrams

json-and-search.redisredis
127.0.0.1:6379> JSON.SET product:1 $ '{"name":"Laptop Pro 14","brand":"acme","price":1299,"stock":12,"tags":["laptop","14in"]}'
OK
127.0.0.1:6379> JSON.SET product:2 $ '{"name":"Laptop Air 13","brand":"acme","price":899,"stock":0,"tags":["laptop"]}'
OK
127.0.0.1:6379> JSON.NUMINCRBY product:1 $.stock -1
"[11]"
127.0.0.1:6379> JSON.GET product:1 $.name $.stock
"{\"$.name\":[\"Laptop Pro 14\"],\"$.stock\":[11]}"

127.0.0.1:6379> FT.CREATE idx:product ON JSON PREFIX 1 product: SCHEMA $.name AS name TEXT $.brand AS brand TAG $.price AS price NUMERIC SORTABLE $.stock AS stock NUMERIC
OK
127.0.0.1:6379> FT.SEARCH idx:product "@brand:{acme} @price:[800 1500] @stock:[1 +inf]" SORTBY price ASC RETURN 2 name price
1) (integer) 1
2) "product:1"
3) 1) "name"
   2) "Laptop Pro 14"
   3) "price"
   4) "1299"
127.0.0.1:6379> FT.AGGREGATE idx:product "*" GROUPBY 1 @brand REDUCE COUNT 0 AS products
1) (integer) 1
2) 1) "brand"  2) "acme"  3) "products"  4) "2"

Interview problem

The problem

Fast product filtering

The product listing page filters by brand, price range and in-stock, sorted by price, with 200K products and 5K queries/sec. PostgreSQL struggles with the combination of filters and sort. Would you use the Redis Query Engine? How do you keep it in sync?

You're given

  • 200K products
  • 5K filter queries/sec
  • Price and stock change often
  • PostgreSQL is the source of truth

The interviewer follows up

01

Why not Elasticsearch?

Explain it without notes

01

How does the Query Engine keep indexes up to date, and what does that mean for write performance?

Practice

01

Index hashes of users (user:{id} with name, country, age) and query users from India aged 25–35 sorted by age.

Trade-offs

  • ↔

    Query Engine: millisecond queries on hot data with one fewer system, but more memory, slower writes, and a sync pipeline from the source of truth.

  • ↔

    JSON documents give nesting and path updates; hashes are more compact for flat objects.

Done when you can

  • I can store and update JSON by path.

  • I can create an index and write filter, sort and aggregate queries.

  • I can design sync from a database with versioning and rebuilds.