jsonredisjsonpathredisearchredisjson

Retrieve all array elements if child array contains a certain element in JSON/RediSearch


I am using Redis with RedisJSON module and RediSearch, and I have some entries such as those below.

JSON.SET uuid_1 $ '{ "type": "game1", "players": ["player1", "player2"] }'
JSON.SET uuid_2 $ '{ "type": "game1", "players": ["player3", "player2"] }'

What I want to achieve is some sort of query that returns both the uuids and the whole array, when such array contains some target elements.

For example, when I query:

I have also checked out this answer, but I cannot fully reproduce it in my case.

What I was able to get is first to create the index:

 FT.CREATE idx ON JSON SCHEMA '$.players[*]' AS players TAG $.type AS gameType TEXT

and then either retrieve only the uuids:

127.0.0.1:6379> FT.SEARCH idx @players:{player2} NOCONTENT
1) (integer) 2
2) "uuid_1"
3) "uuid_2"

or the whole key

127.0.0.1:6379> FT.SEARCH idx @players:{player2}
1) (integer) 2
2) "uuid_1"
3) 1) "$"
   2) "{\"type\":\"game1\",\"players\":[\"player1\",\"player2\"]}"
4) "uuid_2"
5) 1) "$"
   2) "{\"type\":\"game1\",\"players\":[\"player3\",\"player2\"]}"

Unfortunately, if I want to retrieve only the player attribute, it seems that is incomplete and it returns me only the first element:

127.0.0.1:6379> FT.SEARCH idx @players:{player2} RETURN 1 players
1) (integer) 2
2) "uuid_1"
3) 1) "players"
   2) "player1"
4) "uuid_2"
5) 1) "players"
   2) "player"

127.0.0.1:6379> FT.SEARCH idx @players:{player1} RETURN 1 players
1) (integer) 1
2) "uuid_1"
3) 1) "players"
   2) "player1"

Solution

  • This is a bug in early dialects of Search that wasn't corrected in the spirit of preserving backward compatibility. You need to tell Search to use at least DIALECT 3 to get the entire array back.

    127.0.0.1:6379> FT.SEARCH idx @players:{player2} RETURN 1 players DIALECT 3
    1) (integer) 2
    2) "uuid_1"
    3) 1) "players"
       2) "[\"player1\",\"player2\"]"
    4) "uuid_2"
    5) 1) "players"
       2) "[\"player3\",\"player2\"]"
    
    127.0.0.1:6379> FT.SEARCH idx @players:{player1} RETURN 1 players DIALECT 3
    1) (integer) 1
    2) "uuid_1"
    3) 1) "players"
       2) "[\"player1\",\"player2\"]"
    

    You can set the default dialect when you start Redis or by setting a configuration option in when Redis is running:

    $ redis-server --loadmodule ./redisearch.so DEFAULT_DIALECT 3
    
    FT.CONFIG SET DEFAULT_DIALECT 3
    

    Also, there's a handy dandy web page with all the basic dialect info you might care to know.