Как извлечь все значения distint для указанного ключа c внутри JSONField в Django, работающем на Postgres? - PullRequest
0 голосов
/ 13 февраля 2020

Сводка:

Для раскрывающегося списка мне нужно вычислить различные значения для указанного ключа c, хранящегося внутри JSONField в таблице в базе данных Postgres. В худшем случае: таблица содержит 1-10 миллионов записей.

Справочная информация:

Я разрабатываю установку, в которой у меня есть несколько развертываний (по одному для каждого клиента). Каждое развертывание содержит сервер и несколько клиентов. Журналы постоянно публикуются от клиентов к бэкэнду. Эти журналы будут содержать поле log_meta, которое включает в себя ключ с именем origin, которое описывает, откуда пришла запись в журнале. От клиента к клиенту значение origin может варьироваться, и я не хочу применять ограниченный набор значений для origin, но в целом они обозначают среду, в которой работает клиент; «DEV» и «PRODUCTION» являются потенциальными значениями для origin. На практике в одном развертывании может быть только 1-2 различных значения для origin. Ожидается, что количество бревен будет в диапазоне 1-10 миллионов.

from jsonfield import JSONField
from django.db import models

class Log(models.Model)
    # Other fields
    log_json = JSONField(default=list)
    log_meta: JSONField(default=dict) # Will contain a key named origin

В «интерфейсе администратора» я хочу поддержать, что администратор может фильтровать (с помощью раскрывающегося списка), чтобы видеть только журналы, поступающие из указанного c источника. Для этого мне нужно извлечь отдельные значения для поля origin.

Как можно вычислить этот набор различных значений в Django, учитывая, что в некоторых случаях число журналов может находиться в диапазоне 1-10 миллионов?

То, что я уже пробовал :

  • Ничего, поскольку я не знаю, как это можно сделать.

Дополнительная информация :

  • Бэкэнд записывается в Django, используя Postgres в качестве базы данных.
  • Если невозможно вычислить значения на лету, моя альтернатива состоит в том, чтобы непрерывно создавать набор различных значений по мере появления журналов. Я считаю это вторым вариантом, поскольку он вводит дополнительное состояние; если возможно, я предпочитаю просто вычислить / получить набор вместо этого.

1 Ответ

1 голос
/ 13 февраля 2020

QuerySet для выполнения требуемого выбора:

Log.objects.filter(
    # some filtering if required
    log_meta__origin__isnull=False
).order_by().values_list('log_meta__origin').distinct()

order_by() предназначен для очистки любого заказа, уже присутствующего в QuerySet, чтобы позволить нам сделать distinct() вызов позже.


Его «эффективность» - это совершенно другой и субъективный вопрос.

PostgreSQL необходимо просмотреть все записи, чтобы выполнить этот выбор.

Одна из возможностей - добавить индексирование только в это одно поле JSON (как в этом SO вопросе )

Поскольку этот тип выбора не требует частого выполнения (то есть различные источники довольно стабильны, вы можете, например, кэшировать список отдельных значений и обновляйте его периодически) - используйте PostgreSQL Материализованные представления и обновляйте их периодически / по требованию (или просто сохраняйте список в кэше (Redis) вместо Материализованных представлений).

...