【发布时间】:2021-10-22 14:28:07
【问题描述】:
我的参加者表有一个 jsonb 数组字段,名为 eventfilters。
鉴于与eventfilters 具有相同签名(表单)的查询过滤器数组,我需要通过查询过滤器值选择针对此eventfilters 字段过滤的与会者。
以下是查询过滤器和eventfilters 字段的示例:
eventfilters 字段如下所示:
[
{
"field": "Org Type",
"selected": ["B2C", "Both", "Nonprofit"]
},
{
"field": "Job Role",
"selected": ["Customer Experience", "Digital Marketing"]
},
{
"field": "Industry Sector",
"selected": ["Advertising", "Construction / Development"]
}
]
查询过滤器可能如下所示:
[
{
"field": "Org Type",
"selected": ["B2C", "Nonprofit"]
},
{
"field": "Industry Sector",
"selected": ["Advertising"]
}
]
因此,eventfilters 字段和查询过滤器始终具有相同的签名:
Array<{"field": text, "selected": text[]}>
给定上面的查询过滤器和eventfilters,过滤逻辑如下:
- 选择具有
eventfilters字段的所有与会者,例如:-
selected数组和与会者的field: "Org Type"(eventfilters) 包含selected数组中存在的任何值以及查询过滤器的“组织类型”字段; 和 -
selected数组和与会者的field: "Industry Sector"(eventfilters) 包含selected数组中存在的任何值以及查询过滤器的“行业部门”字段。
-
查询过滤器数组可以有不同的长度和不同的元素,但总是具有相同的签名(形式)。
我能想到的是上述逻辑,但不是and 用于查询过滤器中的每个元素,而是or:
select distinct attendee.id,
attendee.email,
attendee.eventfilters
from attendee cross join lateral jsonb_array_elements(attendee.eventfilters) single_filter
where (
((single_filter ->> 'field')::text = 'Org Type' and (single_filter ->> 'selected')::jsonb ?| array ['B2C', 'Nonprofit'])
or ((single_filter ->> 'field')::text = 'Industry Sector' and (single_filter ->> 'selected')::jsonb ?| array ['Advertising'])
);
基本上我需要将上面查询中where 子句中的or 更改为and,但这显然行不通。
where 子句将动态生成。
这是我现在如何生成它的示例(它是javascript,但我希望你能掌握这个想法):
function buildEventFiltersWhereSql(eventFilters) {
return eventFilters.map((filter) => {
const selectedArray = filter.selected.map((s) => `'${s}'`).join(', ');
return `((single_filter ->> 'field')::text = '${filter.field}' and (single_filter ->> 'selected')::jsonb ?| array[${selectedArray}])`;
}).join('\nor ');
}
or 和and 在逻辑上的简单交换,在实现上似乎有很大的不同。我想使用jsonpath 来实现它会更容易,但我的 postgres 版本是 11 :(
如何实现这样的过滤?
PS:create table 和insert 复制代码:https://pastebin.com/1tsHyJV0
【问题讨论】:
标签: postgresql jsonb postgresql-11 cross-join postgresql-json