Django: фильтр JSONField с несколькими вложенными массивами
У меня есть JSONField, называется metadata
на моей модели в Джанго.
Данные в этих полях могут выглядеть примерно так
{
"vis": {
"plots": [
// some objects here
{
"id": 1,
"x": "foo",
"y": "bar",
"externalData": [
// some objects here
{
"x": "fa",
"y": "so",
"source": {
"name": "FINDME",
"location": "some other address"
}
},
// some more objects here
]
},
// some more objects here
],
"somethingElse": []
},
"moreStuff": {}
}
Я хочу иметь возможность фильтровать модели, которые имеют "name": "FINDME"
в externalData
объект (с любым индексом), внутри plots
объект (также с любым индексом).
Я изначально пробовал
MyModel.objects.filter(metadata__vis__plots__externalData__source__name='FINDME')
Не хорошо. Потом я попробовал
MyModel.objects.filter(metadata__vis__plots__externalData__source__contains={'name':'FINDME'})
Не хорошо. Потом я попробовал
MyModel.objects.filter(metadata__vis__plots__externalData__contains=[{'source': {'name':'FINDME'}}])
Все еще не повезло. Наконец я попробовал
MyModel.objects.filter(metadata__vis__plots__contains=[{'externalData':[{'source': {'name': 'FINDME'}}]}])
По-прежнему нет хитов.
Очевидно, я делаю все это неправильно.
Есть идеи?
РЕДАКТИРОВАТЬ: я добавил несколько комментариев в JSON, чтобы прояснить, что у меня не только один объект в каждом из моих массивов. Я пытаюсь найти "сюжет" по произвольному индексу и "externalData" по произвольному индексу, который содержит "source": {"name": "FINDME"}
,
1 ответ
Поскольку "plots" является индексом, вам необходимо представить этот индекс в вашем содержимом. Структура вашего содержимого должна соответствовать JSON, начиная с первого массива. Каждый уровень массива в вашем JSON должен быть представлен в содержащем =
Это проще показать, чем сказать. Как это:
MyModel.objects.filter(
metadata__vis__plots__contains=[{'externalData': [{'source': {'name': 'FINDME'}}]}]
)
У вас есть список dicts внутри вашего JSON, поэтому вам нужно добавить индекс к вашему запросу
MyModel.objects.filter(
metadata__vis__plots__0__externalData__contains=[{"source": {"name": "FINDME"}}])
# ^^^^^