Home > database >  Function radians(jsonb) does not exist
Function radians(jsonb) does not exist

Time:10-17

I have a location column of type jsonb in my issue_points table:

{
  "geo": {
    "lat": 57.994434,
    "lng": 78.35716
  },
  "fias": {
    "city": "some city fias code",
    "region": "some region fias code"
  },
  "address": "some address"
}

Using the Laravel DB facade, I want to find pickup points relative to the received coordinates using the Haversine formula:

select * from "issue_points" where acos(
            sin(radians(?))
            * sin(radians(location->'geo'->'lat'))
              cos(radians(?))
            * cos(radians(location->'geo'->'lat'))
            * cos(radians(?)- radians(location->'geo'->'lng'))
        ) * 6371 <= 20 order by "updated_at" desc

The problem is that if I want to get lat or lng using location->'geo'->'lat', the following postgresql exception is thrown:

"SQLSTATE[42883]: Undefined function: 7 ERROR: function radians(jsonb) does not exist\nLINE 3: * sin(radians(location->'geo'->'lat'))\n
^\nHINT: No function matches the given name and argument types. You might need to add explicit type casts. (SQL: select * from "issue_points" where acos(\n sin(radians(55.03441))\n

  • sin(radians(location->'geo'->'lat'))\n cos(radians(55.03441))\n * cos(radians(location->'geo'->'lat'))\n * cos(radians(73.46783)- radians(location->'geo'->'lng'))\n ) * 6371 <= 20 order by "updated_at" desc)",

p.s If you use atomic fields with scalar data types: lat (float) and lng (float), and try to use the following code, then issue items will return correctly:

select * from "issue_points" where acos(
            sin(radians(?))
            * sin(radians(lat))
              cos(radians(?))
            * cos(radians(lat))
            * cos(radians(?)- radians(lng))
        ) * 6371 <= 20 order by "updated_at" desc

CodePudding user response:

Every operator and function has a type. In the case of the -> you are using it is jsonb => jsonb - it can't be anything else really, your result could be a scalar value, an object, an array, an array of objects contiaining...

So - if you are confident that the values you are extracting will always have the type you expect then you can do: cos(radians( (location->'geo'->'lat')::double precision )).

However, if you do know that your json is always structured like this then there's no reason to make it json is there?

  • Related