如何使用 StringAgg 或 ArrayAgg 连接多个子行中的一列来注释 django 查询集?

Posted

技术标签:

【中文标题】如何使用 StringAgg 或 ArrayAgg 连接多个子行中的一列来注释 django 查询集?【英文标题】:How do I annotate a django queryset with StringAgg or ArrayAgg concatenating one column from mulitple children rows? 【发布时间】:2019-07-10 21:53:04 【问题描述】:

Documents 是父表。 Paragraphs 是子表。

用户根据各种搜索条件过滤文档。 然后我希望用文本查询过滤的某些段落来注释文档。 相同的文本查询用于过滤文档并对其进行排名(SearchRank)。这样的排名使得必须从 Documents 开始,用 Paragraphs 进行注释,而不是从 Paragraphs 开始,按 Document 分组。

将段落中多行中的一个文本字段连接起来的 postgresql 方法如下:

SELECT array_to_string(
ARRAY(
SELECT paragraph.text
FROM paragraph
WHERE document id = '...'
ORDER BY paragraph.number),
', ');

我正在尝试将其翻译成 django 编码。

我尝试了许多 django 方法,但无济于事。 我可以注释 1 段。 Query_sum 是根据用户输入构建的 Q() 对象。

results = Documents.filter(Query_sum)

sub_paragraphs = Paragraphs.filter(Query_sum).filter(document=OuterRef('id'))

results = results.annotate(paragraphs=Subquery(sub_paragraphs.values('text')[:1], output_field=TextField()))

当我摆脱切片 [:1] 时,问题就开始了。

results = results.annotate(paragraphs=Subquery(sub_paragraphs.values('text'), output_field=TextField()))

然后我收到以下错误: “作为表达式的子查询返回的不止一行”。

为了解决这个问题,我尝试使用 ArrayAgg 和 StringAgg。 我弄得一团糟;-)

文档查询集(结果)应使用相关段落列表 (ArrayAgg) 或由任何分隔符分隔的段落字符串 (StringAgg) 进行注释。

知道如何进行吗?不胜感激

【问题讨论】:

您要返回按与搜索匹配的文档相关的段落数排序的文档? 【参考方案1】:

我们可以使用 annotate with Sum, Case and When 对文档进行注释和排序,其中包含与查询匹配的段落数

documents = Document.objects.annotate(
    matches=Sum(Case(
        # This could depend on the related name for the paragraph -> document relationship
        When(paragraphs__text__icontains=search_string, then=Value(1)),
        default=Value(0),
        output_field=IntegerField(),
    )))
).order_by('-matches')

然后,为了获得与每个文档的查询匹配的所有段落,我们使用prefetch_related。我们可以使用Prefetch 对象来过滤预取操作

documents = documents.prefetch_related(Prefetch(
    'paragraphs',
    queryset=Paragraph.objects.filter(text__icontains=search_string),
    to_attrs='matching_paragraphs'
))

然后您可以按排序顺序遍历文档,它们将具有包含所有匹配段落的属性“matching_paragraphs”

【讨论】:

我喜欢它!简约之美。我不得不稍微调整 Prefetch,用 'paragraph_set' 而不是 'paragraphs' 和 'to_attr' 而不是 'to_attrs'。非常感谢! ?

以上是关于如何使用 StringAgg 或 ArrayAgg 连接多个子行中的一列来注释 django 查询集?的主要内容,如果未能解决你的问题,请参考以下文章

在带有 ORDER BY 的子选择中使用 JSON_ARRAYAGG 会出错

SELECT JSON_ARRAYAGG FROM TABLE 名称作为参数问题

CVE-2020-7471-Django SQL注入漏洞复现

pandas agg函数使用方法

如何在 Bigquery 中结合 Cross Join 和 String Agg

如何将 Bigquery 中的 Cross Join 和 String Agg 与日期时间差结合起来