Redis®*: Search and JSON
Store JSON documents and query them efficiently with the Redis query engine
👋 Welcome to the Stackhero documentation!
Stackhero offers a ready-to-use Redis cloud solution that provides a host of benefits, including:
Redis Commanderweb UI included.- Unlimited message size and transfers.
- Effortless updates with just a click.
- Optimal performance and robust security powered by a private, dedicated infrastructure.
Save time and simplify your life: it only takes 5 minutes to try Stackhero's Redis cloud hosting solution!
Your Redis instance on Stackhero includes all modules available in Redis Open Source. These modules make Redis much more than a cache: you can store real JSON documents, index them, and run 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. You can 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 massive 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 itself. These enable efficient vector similarity search for embeddings and are always available on your service. No configuration is needed.
Enabling the modules
Modules are disabled by default. This ensures existing services keep their original behavior 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 typically completes in 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 part of Redis itself.
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
You can store documents natively as JSON, instead of serializing them as strings:
JSON.SET product:1 $ '{"name":"Espresso machine","brand":"Bianca","price":459,"tags":["coffee","kitchen"],"stock":12}'
This approach lets you 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 workflow saves effort and reduces errors. For example, decrementing a stock counter does not require reading, parsing, and rewriting the entire document in your application. Instead, it happens safely and immediately on the server.
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 keeps it up to date automatically 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
Now you can run queries like:
# 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, so you can 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 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 different datasets. - Indexes use your plan's memory, just like your data. Large text or vector indexes can be significant, so you can 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 briefly 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.