Estou usando StringAgg
e order
da seguinte forma:
# Get order column & annotate with list of credits
if request.POST.get('order[0][name]'):
order = request.POST['order[0][name]']
if order == 'credits_primary':
releases = releases.annotate(credits_primary=StringAgg(
'credits__entity__name',
delimiter=', ',
filter=Q(credits__type='primary'),
ordering='credits__id'
))
elif order == 'credits_secondary':
releases = releases.annotate(credits_secondary=StringAgg(
'credits__entity__name',
delimiter=', ',
filter=Q(credits__type='secondary'),
ordering='credits__id'
))
else:
order = 'title'
# Order releases
if request.POST.get('order[0][dir]') == 'desc':
releases = releases.order_by(F(order).desc(nulls_last=True), 'title')
else:
releases = releases.order_by(F(order).asc(nulls_last=True), 'title')
for release in releases:
try: print(release.credits_primary)
except: pass
try: print(release.credits_secondary)
except: pass
Isso por si só funciona exatamente como esperado: a ordem é o que eu espero e print
retorna os valores que eu espero.
Entretanto, quando aplico um filter
antes disso, onde o resultado inclui múltiplas instâncias do mesmo release
, o credits__entity__name
s será repetido ou omitido para aquela versão, dependendo de quantos resultados houver para o(s) campo(s) que estão sendo filtrados, apesar de usar distinct
.
Abaixo está o que filter
estou aplicando que afeta a agregação (aplicado antes StringAgg
):
# Other filters...
# Filter by Search
if request.POST.get('search[value]'):
query = Q()
search = request.POST['search[value]']
query.add(Q(title__icontains=search), Q.OR)
query.add(Q(tags__tag__name__icontains=search), Q.OR)
query.add(Q(credits__entity__name__icontains=search), Q.OR)
releases = releases.filter(query)
# Make sure items aren't repeated
releases = releases.distinct()
Não tenho certeza se entendi seu caso de uso, mas se o problema é que você obtém duplicatas em sua agregação, talvez você possa tentar usar
distinct
em suas agregações de strings:https://docs.djangoproject.com/fr/5.1/ref/contrib/postgres/gregtes/#stringagg
O filtro olha para (outras) relações um-para-muitos ou muitos-para-muitos. Isso significa que isso resultará em
LEFT OUTER JOIN
que começará a agir como um multiplicador. O mesmo funciona com outros agregados, comoSUM
eCOUNT
.De fato, se você apenas agregar, a consulta ficará assim:
e isso é bom, porque queremos agregar as entidades, então, por versão, obtemos todas as entidades.
Mas agora, se filtrarmos por exemplo pelas tags, fica assim:
Isso significa que os nomes de entidade para uma versão em que uma das duas tags correspondem serão repetidos uma vez, mas onde ambas correspondem, serão incluídos duas vezes .
O
Q(credits__entity__name__icontains)
que piora ainda mais a situação: isso será adicionado à tabelac
e, portanto, entidades quecredits
tiverem duas ou mais correspondências serão incluídas muitas vezes, enquanto as entidades de uma versão que não corresponder a um determinado crédito não serão mais incluídas.O divisor menos comum de todos esses fenômenos é provavelmente que você deve ter muito cuidado ao fazer agregações quando fizer
JOIN
s, especialmente se várias tabelas nas quais os JOINs são carregados estiverem envolvidas.O que você provavelmente pode fazer é criar uma
Subquery
expressão [Django-doc] que, portanto, não seja impactada pelas tabelas "externas" e pelos arquivosJOIN
.