13

I have a Postgres table that contains a JSON field, which identifies the images associated with the given record. The contents of the field look like this:

 {"photo-verification": 
   {"photos": [
     {"type": "photo-verification", "fileName": "4f35a880-e9a0-43f9-a31e-1bb8b765d04d", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T20:25:39.706Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T20:25:39.706Z"},
     {"type": "photo-verification", "fileName": "3a104d07-dc48-4f59-b83f-06cd35a21dae", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T22:31:09.808Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T22:31:09.808Z"}
     ]
   }
}

A record can have 0 or more associated images - if there are no images, then the whole field will be empty. I am trying to write a query to determine how many images are associated with a given record. The end result should be a count of how many records have one image, and how many have more than one. If I query the top level of the JSON, like so:

select n.images->'photo-verification' from notes n;

I can get the inner JSON, which contains the array of photos, but if I try to dig deeper, I get no results. My thought was that I could do something along the lines of

select array_length(n.images->'photo-verification'->'photos', 1) from notes n;

or

select json_array_length(n.images->'photo-verification'->'photos') from notes n;

but I end up getting errors and a hint that maybe I should consider casting.

I'm just starting my dive into Postgres, so I'm still trying to wrap my head around some of finer points of the query language. I will continue to research, but any help or insight that someone might provide would be greatly appreciated.

Edit:

So, I thought that I might simplify the problem by creating a view that only has the 'photos' JSON and filters out all of the empty fields:

CREATE VIEW photos as SELECT n.images->'photo-verification' as photo FROM notes.notes n where (n.images->'photo-verification')::text != '';

It worked, in that I now have a view with a JSON column that looks like this:

   {"photos": [
     {"type": "photo-verification", "fileName": "4f35a880-e9a0-43f9-a31e-1bb8b765d04d", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T20:25:39.706Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T20:25:39.706Z"},
     {"type": "photo-verification", "fileName": "3a104d07-dc48-4f59-b83f-06cd35a21dae", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T22:31:09.808Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T22:31:09.808Z"}
     ]
   }

However, if I try

select json_array_length(photo) from photos;

I get:

ERROR: cannot get array length of a scalar

If I try

select json_array_length(photo->'photos') from photos;

I get a bunch of blank records.

I must be missing something here...

2 Answers 2

9
create temp table t (id int, data json);
insert into t values 
(1, 
'{"photo-verification": 
   {"photos": [
     {"type": "photo-verification", "fileName": "4f35a880-e9a0-43f9-a31e-1bb8b765d04d", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T20:25:39.706Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T20:25:39.706Z"},
     {"type": "photo-verification", "fileName": "3a104d07-dc48-4f59-b83f-06cd35a21dae", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T22:31:09.808Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T22:31:09.808Z"}
     ]
   }
}'),
(2, 
'{"photo-verification": 
   {"photos": [
     {"type": "photo-verification", "fileName": "4f35a880-e9a0-43f9-a31e-1bb8b765d04d", "mimeType": "image/jpeg", "createdBy": "jmlittm", "createdTs": "2016-06-20T20:25:39.706Z", "delFlag": false, "updatedBy": "jmlittm", "updatedTs": "2016-06-20T20:25:39.706Z"}
     ]
   }
}')
;

select id, json_array_length(data->'photo-verification'->'photos')
from t;

Or, if you are interested in some specific field:

select json_array_elements(data->'photo-verification'->'photos')->>'fileName' as fileName
from t;
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, mcNets - that's exactly what I'm looking for. Interestingly, if I run that query, straight from the table - select id, json_array_length(images->'photo-verification'->'photos') from notes.notes where images::text != '';, I get all of the IDs, but the length field is empty. I'm using a foreign data wrapper, but the data still looks okay when it comes through. Perhaps if I did a SELECT INTO, and put it in a temp table, I might have better luck. <shrug>
9

Seems casting to JSON is needed:

select json_array_length((images->'photo-verification'->'photos')::json)
from notes;

1 Comment

Well, I tried select count(*) from notes where json_array_length((images->'photo-verification'->'photos')::json) > 1; and it came back with a count of zero. It does seem like that would be the right track, though. Thanks for looking!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.