'Django - Postgresql - JSON Field - #>> operator - Index of out range
In a django project which is using postgresql DB, there is a collection called 'table1' which has a JSON field called 'data'. In this JSON field, we will be storing an email against a dynamic key. For ex:
ID | DATA
1 | '{"0_email": "[email protected]"}'
2 | '{"3_email": "[email protected]"}'
3 | '{"1_email": "[email protected]"}'
Problem Statement:
Filter out the rows in which "[email protected]" exists in the "data" field.
My Approach:
from django.db import connection
@transaction.atomic
def run(given_email):
with connection.cursor() as crsr:
crsr.execute(
"""
DECLARE mycursor CURSOR FOR
SELECT id, data
FROM table1
WHERE
data #>> '{}' like '%\"%s\"%'
""",
[given_email]
)
while True:
crsr.execute("FETCH 10 FROM mycursor")
chunk = crsr.fetchall()
# DO SOME OPERATIONS...
Explanation for data #>> '{}' like '%\"%s\"%':
- I am using the
#>>operator to get object at specific path of JSON as text. - I am providing
'{}'empty path so that I will get the complete JSON as a text. - From this stringified JSON, I am checking if the given_email ([email protected] from the above example) is present
Then, I have pointed this function to a API in django in which I will get the given_email in payload. I am facing the below error which triggering this function:
Traceback (most recent call last): File "project/lib/python3.9/site-packages/django_extensions/management/debug_cursor.py", line 49, in execute return utils.CursorWrapper.execute(self, sql, params) File "project/lib/python3.9/site-packages/django/db/backends/utils.py", line 67, in execute File "project/lib/python3.9/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers File "project/lib/python3.9/site-packages/django/db/backends/utils.py", line 87, in _execute self.db.validate_no_broken_transaction() IndexError: tuple index out of range
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "", line 1, in File "project/lib/python3.9/site-packages/django_extensions/management/debug_cursor.py", line 54, in execute raw_sql = raw_sql[:truncate] TypeError: 'NoneType' object is not subscriptable
Observations:
- I don't think there is anything wrong with the query. In fact, I have tried this query in DBeaver and I am getting the expected response.
- I am suspecting that the
'{}'part in the query is causing some issue. So, I have tried to replace it with'\\{\\}','{{}}'but it didn't work.
Solution 1:[1]
First, '{}' is interpreted as a text whereas a json path is of type text[].
So you should cast it as text[] in your query : WHERE data #>> '{}' :: text[] like '%\"%s\"%'
Then data #>> '{}' :: text[] could be simplified as data :: text which will provide the same result.
Finally, you convert your json data into a text and then you use the pattern matching like operator. This solution may provide some unexpected results with some values which contains the expected email as a substring but which are not equal to that expected email.
In order to have the exact result for the expected email, you should use a jsonb function, for example :
WHERE jsonb_path_exists(data :: jsonb, ('$.* ? (@ == "' || expected_email || '")') :: jsonpath)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Edouard |
