Why do these two queries give different result in postgresql ?
select '{"items":["foo", "bar"]}'::jsonb->'items';
select to_jsonb('{"items":["foo", "bar"]}'::text)->'items';
the first one returns: ["foo", "bar"]
and the second one returns [NULL]
2
Answers
The documentation for
to_jsonb()
says this (emphasis mine):In other words, it isn’t parsing JSON from string, it’s creating a JSON string from your text.
"{"items":["foo", "bar"]}"
unknown
constant, the second one converts a constant of an already knowntext
type, to another type.PostgreSQL treats single-quoted constants as type
unknown
. When you add::jsonb
, it verifies if the constant is a validjsonb
literal and assigns the type.It already told you exactly that, which is why you had to add
::text
before passing the constant toto_jsonb()
:And once you added
::text
,to_jsonb()
mapped the whole thing from a plain PostgreSQLtext
type to JSON internalstring
type, ignoring what’s inside it.->
returnednull
because the value is now a lonely JSON string, not an object with keys in it, so the path->'items'
isn’t valid.The only valid path in there is no path at all:
#>>'{}'
(that’s an empty array of keys that forms a path with no steps)Which is how you can get back your
text
-type value back out of that JSON.The clever thing about
to_jsonb()
is how you can automagically map out your tables tojsonb
:Which the cast won’t do: