Search code examples
redisnode-redisredis-cliredisjsonredisclient

RedisJSON - Manipulating the JSON array of objects (Using Node Redis client)


This is the data [ { "senderID": "64d9c926c17fd183a93d5e35", "receiverID": "64d9c92dc17fd183a93d5e39", "timestamp": "2023-08-14T07:39:45.946Z", "content": "bru", "status": "delivered", "type": "chat", "messageID": "8188946b-67e4-4d86-a927-32842361825c" },........ ]

I just want to select all the status sent and change status to delivered


 if (messageIDs.length === 0) {
        this.chatRepository.jsonSet(
          `rooms:${room?.roomID}`,
          room?.status,
          `$.*[?(@.status=="sent")].status`,
        );
      }


  async jsonSet(key: string, value: any, option?: string) {
    if (!option) {
      option = '$';
    }
    console.log(key, option, value)
    await this.redisProvider.publisher.json.set(key, option, value);
  }

I am failing to pass a string there called 'sent'

Redis Query that failed

JSON.SET rooms:64d9c926c17fd183a93d5e35-64d9c92dc17fd183a93d5e39 $.*[?(@.status=="sent")].status '"delivered"' 

Help is appreciated, I am using npm with redis node version is 20 and redis probably latest version as well

Note: This works both on REDIS CLI and from node Client

JSON.SET rooms:64d9c926c17fd183a93d5e35-64d9c92dc17fd183a93d5e39 $.[*].status '"delivered"'

I have tried

$.*[?(@.status=="sent")]

.*[?(@.status=="sent")]

$.*[?(@.status=="'sent'")]

$.[?(@.status==sent)]

I am failing to pass a string there called 'sent'

EDIT: Have tried to set with the given approaches

''' this.chatRepository.jsonSet( rooms:${rooms?.roomID}, rooms?.status, "$.[?.(@.status=='sent')].status" ); Error: ERR new objects must be created at the root '''


Solution

  • Some of these JSONPath things can be tricky. This one is invalid. What it does is start at the root with $. Then the .* selects all the fields on the object in the root. Since there are none, it returns none. Then, assuming those not-found fields are arrays, it matches each object in those array for a status property of sent. Where this matches, it selects those properties.

    I like to use jsonpath.com to test out my JSON and corresponding paths. Makes the troubleshooting easier.

    Regardless, I got it to work with the following JSONPath:

    $[?(@.status=='sent')].status
    

    And here it is working from the CLI:

    127.0.0.1:6379> JSON.SET rooms:1234 $ '[ { "senderID": "64d9c926c17fd183a93d5e35", "receiverID": "64d9c92dc17fd183a93d5e39", "timestamp": "2023-08-14T07:39:45.946Z", "content": "bru", "status": "delivered", "type": "chat", "messageID": "8188946b-67e4-4d86-a927-32842361825c" }]'
    OK
    127.0.0.1:6379> JSON.GET rooms:1234 "$[?(@.status=='delivered')].status"
    "[\"delivered\"]"
    127.0.0.1:6379> JSON.GET rooms:1234 "$[?(@.status=='sent')].status"
    "[]"
    

    I just did a JSON.GET but it should work find for JSON.SET too.