Как распаковать результат подзапроса в поле типа списка в результат исходного запроса в peewee? - PullRequest
0 голосов
/ 25 января 2019

Как заставить peewee помещать идентификаторы строк связанной таблицы в дополнительное поле в виде списка в результирующий запрос?

Я хочу сделать менеджер обнаружения дубликатов для медиа-файлов. Для каждого файла на моем компьютере у меня есть запись в базе данных с полями типа

File name, Size, Path, SHA3-512, Perceptual hash, Tags, Comment, Date added, Date changed, etc...

В зависимости от ситуации я хочу использовать разные шаблоны, чтобы использовать записи в таблице как дубликаты.

В самом простом случае я хочу просто видеть все записи, имеющие одинаковый хэш, поэтому я

subq = Record.select(Record.SHA).group_by(Record.SHA).having(peewee.fn.Count() > 1)
subq = subq.alias('jq')
q = Record.select().join(q, on=(Record.SHA == q.c.SHA)).order_by(Record.SHA)
for r in q:
    process_record_in_some_way(r)

и все в порядке. Но есть много случаев, когда я хочу использовать разные наборы столбцов таблицы в качестве шаблонов группировки. Так что в худшем случае я использую все из них, кроме id и столбца «Дата добавления», для обнаружения точных дублирующих строк в базе данных, когда я только что несколько раз читал один и тот же файл, что приводит к монстру вроде

subq = Record.select(Record.SHA, Record.Name, Record.Date, Record.Size, Record.Tags).group_by(Record.SHA, Record.Name, Record.Date, Record.Size, Record.Tags).having(peewee.fn.Count() > 1)
subq = subq.alias('jq')
q = Record.select().join(q, on=(Record.SHA == q.c.SHA and Record.Name == q.c.Name and Record.Date == q.c.Date and Record.Size == q.c.Size and Record.Tags == q.c.Tags)).order_by(Record.SHA)
for r in q:
    process_record_in_some_way(r)

и это не полный список моих полей, просто пример. То же самое я должен сделать для других шаблонов наборов полей, то есть дублировать его список 3 раза в предложении select, группировать предложение подзапроса и затем перечислять их все снова в предложении присоединения.

Я хотел бы просто сгруппировать записи с соответствующим шаблоном, и peewee просто перечисли бы идентификаторы всех членов каждой группы в новое поле списка, например

q=Record.select(Record, SOME_MAJIC.alias('duplicates')).group_by(Record.SHA, Record.Name, Record.Date, Record.Size, Record.Tags).having(peewee.fn.Count() > 1).SOME_ANOTHER_MAJIC
for r in q:
    process_group_of_records(r) # r.duplicates == [23, 44, 45, 56, 100], for example

Как я могу это сделать? Перечисляя одни и те же параметры, я действительно чувствую, что делаю что-то не так.

1 Ответ

0 голосов
/ 25 января 2019

Вы можете использовать GROUP_CONCAT (или для postgres, array_agg), чтобы сгруппировать и объединить список идентификаторов / имен файлов, что угодно.

Так что для файлов с таким же хешем:

query = (Record
         .select(Record.sha, fn.GROUP_CONCAT(Record.id).alias('id_list'))
         .group_by(Record.sha)
         .having(fn.COUNT(Record.id) > 1))

Это реляционная база данных. Таким образом, вы постоянно и везде имеете дело с таблицами, состоящими из строк и столбцов. Там нет "вложенности". GROUP_CONCAT примерно настолько близко, насколько вы можете получить.

...