#29504 closed Cleanup/optimization (fixed)
Document limitations of using int()able keys with JSONField
| Reported by: | Shaheed Haque | Owned by: | Abheet |
|---|---|---|---|
| Component: | Documentation | Version: | dev |
| Severity: | Normal | Keywords: | |
| Cc: | Carlton Gibson, Clifford Gama | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description (last modified by )
The documentation on performing queries inside JSONField values https://docs.djangoproject.com/en/2.0/ref/contrib/postgres/fields/#key-index-and-path-lookups says:
If the key is an integer, it will be interpreted as an index lookup in an array: >>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
Note the specific mention of array. While this might be true, it is not the whole truth as applied to dict/object. For example, given a dict/object whose keys are strings (as always in JSON) but which look like integers:
"employee": {
"415": {
"email": "Sherlock.Holmes@acme.co.uk",
"mobile": "0700 1234567",
how is one supposed to select the "415" bit? It turns out that the same syntax as for the array case applies:
Foo.objects.filter(snapshot__employee__415__mobile='0700 1234567')
This was not at all obvious to me at least, especially as if the "415" is looked up as the final key in the query, the syntax becomes very different:
Foo.objects.filter(snapshot__employee__has_key='415')
Since I wasted quite a bit of time on this, I thought it might be useful to strengthen the documentation in this area to clarify how to lookup:
- In arrays and dict/objects
- if the key is the final term in the query
- if the key is not the final term in the query
Change History (14)
comment:1 by , 8 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 8 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|---|
| UI/UX: | unset |
| Version: | 2.0 → master |
comment:3 by , 8 years ago
| Cc: | added |
|---|
comment:5 by , 8 years ago
| Has patch: | set |
|---|
comment:6 by , 8 years ago
| Resolution: | → wontfix |
|---|---|
| Status: | new → closed |
| Type: | Uncategorized → Cleanup/optimization |
Closing per discussion on PR.
comment:7 by , 8 days ago
| Cc: | added |
|---|---|
| Has patch: | unset |
| Resolution: | wontfix |
| Status: | closed → new |
| Summary: | JSONField dictionary/object lookup using an "integer" key → Document limitations of using int()able keys with JSONField |
| Triage Stage: | Accepted → Unreviewed |
I think there's enough ambiguity and lack of support across databases to be worth some documentation here. (Thanks Clifford for pointing me at this from #37297.)
On Postgres, string keys that are int()able can't be queried in the usual way unless more lookups are chained afterward, because when len(key_transforms) == 1, we assume any int()able key is an int.
Then, if you do chain more lookups afterward, it works perfectly fine, but only on Postgres, where the #> ARRAY[... syntax is flexible enough to match either keys or indices. Other databases require specific SQL to match either a key or an index.
from django.db import models class Person(models.Model): metadata = models.JSONField() def run(): metadata = { "0": "foo", "zero": "foo", } instance = Person.objects.create(metadata=metadata) # assert Person.objects.filter(metadata__0="foo").exists() # fails assert Person.objects.filter(metadata__zero="foo").exists() # passes metadata = { "0": { "nested": "foo" } } instance = Person.objects.create(metadata=metadata) assert Person.objects.filter(metadata__0__nested="foo").exists() # works on PG only
Given all that, I think we should clarify that int()able keys aren't always queryable?
comment:8 by , 8 days ago
I'd like to work on this ticket. I'll submit a documentation patch clarifying that int()-able keys in JSONField are not always queryable.
comment:10 by , 7 days ago
| Has patch: | set |
|---|---|
| Owner: | changed from to |
| Status: | new → assigned |
comment:11 by , 6 days ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
OK, I'm going to provisionally accept this. If you can put together a patch we can have a look and see if there's a clarification to be made.
I'm half-minded to say
wontfixsince JSON keys must always be strings, and whilst, like'415', they might look like integers, there's no real ambiguity.But lets see what improvement you have in mind. :)