6

I want to filter rows that have gold badges. I am using PG12 and I use new path feature of it.

To clarify, I have a users_tbl table like this:

CREATE TABLE users_tbl (
   ID serial NOT NULL PRIMARY KEY,
   data jsonb NOT NULL
); 

And lets insert values:

INSERT INTO users_tbl (ID, data) values (1, '{"badges": ["gold", "silver"], "another_field": 1}');
INSERT INTO users_tbl (ID, data) values (2, '{"badges": ["silver"], "another_field": 3}');
INSERT INTO users_tbl (ID, data) values (3, '{"badges": ["gold"], "another_field": 4}');

Now when I query like this:

SELECT
  ID, jsonb_path_query("data", '$.badges') AS "badges"
FROM "users_tbl";

I get following result as expected:

+----+--------------------+
+ ID |       badges       +
+----+--------------------+
+ 1  | ["gold", "silver"] +
+----+--------------------+
+ 2  | ["silver"]         +
+----+--------------------+
+ 3  | ["gold"]           +
+----+--------------------+

Now list only have badge matches gold

SELECT
  jsonb_path_query("data", '$.badges') AS "badges"
FROM "users_tbl"
WHERE "badges" @> 'gold';

Expected result:

+----+--------------------+
+ ID |       badges       +
+----+--------------------+
+ 1  | ["gold", "silver"] +
+----+--------------------+
+ 3  | ["gold"]           +
+----+--------------------+

Actual Result:

column "badges" does not exist 

How can I add condition against badges? Or am I doing something not correct? How can I get expected result in my case?

Note: PostgreSQL 12.

Update:

Actually in this example I've used a simple jsonb object. In reality its like this:

{
  "properties": {
    "badges": ["gold", "silver"]
  }
}

So, badges are in properties

3 Answers 3

5

You can use the containment operator:

select
    jsonb_path_query(data, '$.badges') as badges
from users_tbl
where data->'badges' @> '"gold"';

or jsonb_path_exists():

select
    jsonb_path_query(data, '$.badges') as badges
from users_tbl
where jsonb_path_exists(data, '$.badges ? (@[*] == "gold")')
Sign up to request clarification or add additional context in comments.

2 Comments

I've made an update at the bottom. Can you inspect it please?
No need to inspect. I just added secondary path and it worked.
2

You can use the ? operator:

SELECT jsonb_path_query("data", '$.badges') AS "badges"
FROM "users_tbl"
WHERE "data" -> 'badges' ? 'gold';

Note: I am unsure that you do need jsonb_path_query() here. This is a set-returning function that does not really seems to make sense in your context. Your query could probably be phrased:

SELECT "data" ->> 'badges' AS "badges"
FROM "users_tbl"
WHERE "data" -> 'badges' ? 'gold';

Demo on DB Fiddle:

| badges             |
| :----------------- |
| ["gold", "silver"] |
| ["gold"]           |

3 Comments

I've made an update at the bottom. Can you inspect it please?
@Pratha: that would be: SELECT "data" -> 'properties' ->> 'badges' AS "badges" FROM "users_tbl" WHERE "data" -> 'properties' -> 'badges' ? 'gold';
Thanks. I just can't decide if I should go with your or jsonb_path_exists from @klin's answer. This column can be NULL, can be empty or may not have properties/badges at all. Does this matters on yours?
1

How can I add condition against badges?

You can't really. As the error message says, it's not a column of the table - that's what you'd need to refer to in the WHERE clause. You cannot take the selection alias to refer to the result value of the expression. You could repeat it

SELECT jsonb_path_query_first("data", '$.badges') AS "badges"
FROM "users_tbl"
WHERE jsonb_path_query_first("data", '$.badges') @> 'gold';

or use a LATERAL subquery:

SELECT badges
FROM "users_tbl", LATERAL jsonb_path_query("data", '$.badges') as badges
WHERE badges @> 'gold';

2 Comments

I got set-returning functions are not allowed in WHERE on first query of yours.
@Pratha Oh, I forgot that jsonb_path_query is a set-returning function - you only expect one array value back. I've changed it to use jsonb_path_query_first, although definitely I would suggest using the simple -> operator as in the other answers, a jsonpath is overkill here. (I just wanted the code to resemble your original more)

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.