Search code examples
jsonpostgresqljsonb

Postgres: Range Query on nested jsonb column


I am using postgres 9.5.4.

From below sample json data stored in jsonb column, I would like to search records matching o['mid'] > 7000

This is sample of one user's record. There will be millions of such users.

{
  "uid": 14105529,
  "o": [
    {
      "mid": 6551,
      "ac": 1913,
      "ip": "144.36.233.44",
      "adw": 5,
      "at": 133000,
      "ad": 151015,
      "aid": 0
    },
    {
      "mid": 7552,
      "ac": 1913,
      "ip": "144.36.233.44",
      "adw": 5,
      "at": 133000,
      "ad": 151015,
      "aid": 0
    },
    {
      "mid": 7553,
      "ac": 1913,
      "ip": "144.36.233.44",
      "adw": 5,
      "at": 133000,
      "ad": 151015,
      "aid": 0
    }
  ]
}

Solution

  • with a_table(jdata) as ( 
    values (
        '{
            "uid":14105529,
            "o":[
                {"mid":6551,"ac":1913,"ip":"144.36.233.44","adw":5,"at":133000,"ad":151015,"aid":0}, 
                {"mid":7552,"ac":1913,"ip":"144.36.233.44","adw":5,"at":133000,"ad":151015,"aid":0},
                {"mid":7553,"ac":1913,"ip":"144.36.233.44","adw":5,"at":133000,"ad":151015,"aid":0} 
            ] }'::jsonb
        )
    )
    
    select jdata->'uid' as uid, value
    from a_table, jsonb_array_elements(jdata->'o')
    where (value->>'mid')::int > 7000;
    
       uid    |                                              value                                               
    ----------+--------------------------------------------------------------------------------------------------
     14105529 | {"ac": 1913, "ad": 151015, "at": 133000, "ip": "144.36.233.44", "adw": 5, "aid": 0, "mid": 7552}
     14105529 | {"ac": 1913, "ad": 151015, "at": 133000, "ip": "144.36.233.44", "adw": 5, "aid": 0, "mid": 7553}
    (2 rows)
    

    The query will be really expensive for a large dataset because of necessity of unnesting the json array with jsonb_array_elements(). There is no index you could use to speed it up.