Создание индекса на вложенном элементе JSONField для Postgres в Django
У меня есть модель Django в моем проекте python с мета-классом, детализирующим ее индексы. Мне интересно, есть ли способ создать индекс, используя вложенный путь к объекту json. В данном случае мы знаем структуру нашего json, и я хотел бы использовать индекс BTree или Hash для конкретного элемента.
Если бы я просто запускал это как необработанный sql, я бы ожидал просто сделать что-то вроде:
CREATE INDEX ON foster_data(root->'level_1'->'level_2'->>'name');
Я надеялся, что смогу сделать что-то подобное в своей модели:
from django.db import models
from django.contrib.postgres import indexes
class ParentGuardians(Facilitators): # which extends models.Model
parent_identifier = models.IntegerField(db_column='p_id', default=None, blank=True,
null=True)
class Meta:
constraints = [
models.UniqueConstraint(fields=['table_id', name='UniqueConstraint for Parents')
]
indexes = [
models.Index(fields=['p_id', ]),
indexes.BTreeIndex(fields=[models.JSONField('{"root": {"level_1": {"level_2": "name"}}}'), ]
, name="jsonb_p_id_idx"),
]
или даже:
...
indexes.BTreeIndex(fields=["root->'level_1'->'level_2'->>'name'", ]
...
Но именованное поле fields хочет только строки и только для того, чтобы они были полем верхнего уровня, определенным в модели.
I'm aware of this questions: Indexing JSONField in Django PostgreSQL but it seems more of a hack and wanted the result generated from the codebase and makemigrations, not to manually edit it. Is this possible more recently?
В Django 3.2 появилась встроенная поддержка этих индексов.
В заданном вопросе, похоже, нет определения JSONField, но если предположить, что это что-то вроде
from django.db import models
class Facilitators(models.Model):
foster_data = models.JSONField()
Для индексации определенного ключа вы комбинируете F-выражение с JSONField path lookup на опции Meta indexes модели :
from django.contrib.postgres.fields import JSONField
class Facilitators(models.Model):
foster_data = models.JSONField()
class Meta:
indexes = [
models.Index(models.F("foster_data__root__level_1__level2__name"), name="foster_data__root__level_1__level2__name_idx"),
]
Это создаст индекс B-дерева. Если вы добавляете их к существующей модели, убедитесь, что makemigrations и migrate.
См. также этот ответ https://stackoverflow.com/a/74619523/