Skip to content

RedisJSON support in Lettuce

Lettuce supports RedisJSON starting from Lettuce 6.5.0.RELEASE.

The driver generally allows three distinct ways of working with the RedisJSON module: * (Default mode) - default JSON parsing using Jackson behind the scenes * (Advanced mode) - custom JSON parsing using a user-provided JSON parser * (Power-user mode) - unprocessed JSON documents that have not gone through any process of deserialization or serialization

Info

In all the above modes, the driver would refrain from processing the JSON document in the main event loop and instead delegate this to the user thread. This behaviour is consistent when both receiving and sending JSON documents - when receiving the parsing is done lazily whenever a method is called that requires the JSON to be parsed; when sending the JSON is serialized immediately after it is passed to any of the commands, but before dispatching the command to the event loop.

Warning

Unless you are using a custom JSON parser you would need to add a dependency to the jackson-databind library in your project. This is because the default JSON parser uses Jackson to parse JSON documents to and from string representations.

Default mode

Best for:

  • Most typical use-cases where the JSON document is parsed and processed

Example usage

RedisURI redisURI = RedisURI.Builder.redis("acme.com").build();
RedisClient redisClient = RedisClient.create(redisURI);
try (StatefulRedisConnection<ByteBuffer, ByteBuffer> connect = redisClient.connect()){
    redis = connect.async();
    JsonPath path = JsonPath.of("$..mountain_bikes[0:2].model");

    JsonParser parser = redis.getJsonParser();
    JsonObject bikeRecord = parser.createJsonObject();
    JsonObject bikeSpecs = parser.createJsonObject();
    JsonArray bikeColors = parser.createJsonArray();

    bikeSpecs.put("material", parser.createJsonValue("\"wood\""));
    bikeSpecs.put("weight", parser.createJsonValue("19"));

    bikeColors.add(parser.createJsonValue("\"walnut\""));
    bikeColors.add(parser.createJsonValue("\"chestnut\""));

    bikeRecord.put("id", parser.createJsonValue("\"bike:13\""));
    bikeRecord.put("model", parser.createJsonValue("\"Woody\""));
    bikeRecord.put("description", parser.createJsonValue("\"The Woody is an environmentally-friendly wooden bike\""));
    bikeRecord.put("price", parser.createJsonValue("\"1112\""));
    bikeRecord.put("specs", bikeSpecs);
    bikeRecord.put("colors", bikeColors);

    String result = redis.jsonSet("bikes:inventory", path, bikeRecord).get();
}

Advanced mode

Best for:

  • Applications that want to handle parsing manually - either by using another library or by implementing their own parser

Example usage

RedisURI redisURI = RedisURI.Builder.redis("127.0.0.1").withPort(16379).build();

try (RedisClient client = RedisClient.create(redisURI)) {
    client.setOptions(ClientOptions.builder().jsonParser(Mono.just(new CustomParser())).build());
    StatefulRedisConnection<String, String> connection = client.connect(StringCodec.UTF8);
    RedisCommands<String, String> redis = connection.sync();
}

Power-user mode

Best for:

  • Applications that do little to no processing on the Java layer

Example usage

JsonPath myPath = JsonPath.of("$..mountain_bikes");
RedisURI redisURI = RedisURI.Builder.redis("127.0.0.1").withPort(16379).build();
try (RedisClient client = RedisClient.create(redisURI)) {
    RedisAsyncCommands<String, String> redis = client.connect().async();
    RedisFuture<List<JsonValue>> bikes = redis.jsonGet("bikes:inventory", myPath);

    CompletionStage<RedisFuture<String>> stage = bikes.thenApply(
            fetchedBikes -> redis.jsonSet("service_bikes", JsonPath.ROOT_PATH, fetchedBikes.get(0)));

    String result = stage.toCompletableFuture().get().get();
}    

Note

The power-user mode is not exclusive to using a custom parser (Advanced mode), as long as the custom parser follows the API contract of the JsonParser, JsonValue, JsonArray and JsonObject interfaces.