Redis®*: Search and JSON
Store JSON documents and query them efficiently with the Redis query engine
👋 Welcome to the Stackhero documentation!
Stackhero provides a ready-to-use Redis cloud solution that delivers numerous advantages, including:
- Redis Commander web interface included.
- Unlimited message size and transfers.
- One-click simplified updates.
- Optimal performance and enhanced security thanks to a private, dedicated infrastructure.
Save time and make your life easier: it only takes 5 minutes to try Stackhero's Redis cloud hosting solution!
Your Stackhero for Redis instance includes all modules available in Redis Open Source. These modules make Redis much more than just a cache: you can store real JSON documents, index them, and perform full-text, numeric, and tag queries directly. There is no need to add another database to your stack.
All four modules below are included in your plan:
- JSON (
JSON.*commands): Adds a native JSON type with JSONPath support, allowing you to read or update individual fields without rewriting the entire document. - Search (
FT.*commands), also known as the Redis query engine: Provides full-text search, secondary indexing, aggregations, and vector search capabilities. - Bloom (
BF.*,CF.*,CMS.*,TOPK.*,TDIGEST.*commands): Probabilistic data structures that efficiently answer questions like "have I already seen this?" over large sets, using minimal memory. - Time series (
TS.*commands): Offers a time series type with retention, downsampling, and aggregation features.
Vector sets (VADD, VSIM) are built directly into Redis. They enable efficient vector similarity search for embeddings and are always available on your service. No configuration is required.
Enabling the modules
Modules are disabled by default. This ensures that existing services retain their original behaviour until you choose to enable new features.
- Open your service in the Stackhero dashboard.
- Go to the service configuration.
- In the Modules section, select the modules you want.
- Save your changes.
Your Redis service will restart with the selected modules loaded. This process usually takes only a few seconds.
Once you store data using a module (such as a JSON document, Bloom filter, or time series), keep that module enabled. Redis cannot access data created by a disabled module, and disabling it will prevent your service from starting. Vector sets are always available, as they are an integral part of Redis.
To check which modules are currently loaded, you can run:
redis-cli -u "rediss://default:<yourPassword>@<XXXXXX>.stackhero-network.com:<PORT_TLS>" MODULE LIST
Storing JSON documents
Instead of serializing your documents as strings, you can store them natively in JSON format:
JSON.SET product:1 $ '{"name":"Espresso machine","brand":"Bianca","price":459,"tags":["coffee","kitchen"],"stock":12}'
This method allows you to read or update individual fields atomically and server-side:
JSON.GET product:1 $.price
# "[459]"
JSON.NUMINCRBY product:1 $.stock -1
# "[11]"
JSON.ARRAPPEND product:1 $.tags '"gift"'
This approach simplifies your workflows and reduces errors. For example, decrementing a stock counter does not require reading, parsing, and rewriting the entire document in your application. The operation is performed instantly and safely on the server side.
You can find the full list of commands in the Redis JSON documentation.
Indexing and searching those documents
You only need to declare an index once. Redis will then automatically keep it up to date for every key matching the chosen prefix, including keys that existed before the index was created.
FT.CREATE productsIndex
ON JSON
PREFIX 1 product:
SCHEMA
$.name AS name TEXT
$.brand AS brand TAG
$.price AS price NUMERIC SORTABLE
$.tags[*] AS tags TAG
You can then run powerful queries, for example:
# Full-text search on the name, with a price range
FT.SEARCH productsIndex "@name:(espresso) @price:[0 500]"
# Exact brand match, sorted by price
FT.SEARCH productsIndex "@brand:{Bianca}" SORTBY price ASC
# Prefix search for autocomplete scenarios
FT.SEARCH productsIndex "@name:(espr*)"
Redis can also handle aggregations directly on the index, allowing you to answer analytical queries without exporting data:
FT.AGGREGATE productsIndex "*"
GROUPBY 1 @brand
REDUCE COUNT 0 AS products
REDUCE AVG 1 @price AS averagePrice
SORTBY 2 @products DESC
If you store your data in plain hashes instead of JSON, you can use ON HASH and standard field names in your schema.
Example: Using Node.js
import { createClient, SCHEMA_FIELD_TYPE } from 'redis';
const client = createClient({ url: process.env.STACKHERO_REDIS_URL_TLS });
await client.connect();
// Create the index at startup
try {
await client.ft.create(
'productsIndex',
{
'$.name': { type: SCHEMA_FIELD_TYPE.TEXT, AS: 'name' },
'$.brand': { type: SCHEMA_FIELD_TYPE.TAG, AS: 'brand' },
'$.price': { type: SCHEMA_FIELD_TYPE.NUMERIC, AS: 'price', SORTABLE: true }
},
{ ON: 'JSON', PREFIX: 'product:' }
);
}
catch (error) {
if (!error.message.includes('Index already exists')) {
throw error;
}
}
await client.json.set('product:1', '$', {
name: 'Espresso machine',
brand: 'Bianca',
price: 459
});
const results = await client.ft.search('productsIndex', '@name:(espresso) @price:[0 500]');
console.log(results.total, results.documents);
await client.quit();
Example: Using Python
import os
import redis
from redis.commands.search.field import TextField, TagField, NumericField
from redis.commands.search.index_definition import IndexDefinition, IndexType
from redis.commands.search.query import Query
r = redis.from_url(os.environ['STACKHERO_REDIS_URL_TLS'], decode_responses=True)
# Create the index at startup
try:
r.ft('productsIndex').create_index(
(
TextField('$.name', as_name='name'),
TagField('$.brand', as_name='brand'),
NumericField('$.price', as_name='price', sortable=True),
),
definition=IndexDefinition(prefix=['product:'], index_type=IndexType.JSON),
)
except redis.ResponseError as error:
if 'Index already exists' not in str(error):
raise
r.json().set('product:1', '$', {
'name': 'Espresso machine',
'brand': 'Bianca',
'price': 459,
})
results = r.ft('productsIndex').search(Query('@name:(espresso) @price:[0 500]'))
print(results.total, results.docs)
Good to know
- Search indexes only work on database 0.
FT.CREATEreturns an error on any other database. If your application uses several logical databases, keep indexable data on database 0, or use key prefixes to separate your datasets. - Indexes use your plan's memory, just like your data. Large text or vector indexes can take up significant space, so monitor
used_memoryin your Prometheus metrics after building them. - Building an index on existing keys runs in the background. Immediately after
FT.CREATE, searches may temporarily return incomplete results. You can monitor the indexing progress withFT.INFO productsIndex. - All module commands are fully available. Every command of every enabled module is ready to use in your service.
To learn more about vector similarity, semantic search, or retrieval-augmented generation, see the vector search guide.