检查 JSONB 列中的数组是否包含另一个数组中的任何值

Check whether array in JSONB column includes any of the values in another array

问题

查找示例数据中的所有记录,其中 foo->bar 至少包含给定数组中的一项,例如[1,2]

示例数据

Record 1 => 'foo': {
  'bar': [1,2]
}

Record 2 => 'foo': {
  'bar': [3,4]
}

Record 3 => 'foo': {
  'bar': [5,7]
}

Record 4 => 'foo': {
  'bar': [1]
}

Record 5 => 'foo': {
  'bar': [2,3]
}

预期结果

Record 1 => 'foo': {
  'bar': [1,2]
}


Record 4 => 'foo': {
  'bar': [1]
}

Record 5 => 'foo': {
  'bar': [2,3]
}

我尝试使用运算符 @>?|,仅当包含所有项目时才首先检查 JSOB 和 returns。第二个问题与类型 JSOB => Integer[]

SQL

SELECT  "some_table".* FROM "some_table" WHERE (foo->'bar' @> '[1,2]'::jsonb);

Rails 范围

scope :for_bar, -> (bars) { where("foo->'bar' @> ?::jsonb", bars.to_json) }

解决这个问题的任何建议。

一种可能的解决方案是使用 jsonb_array_elements() 将 JSON 数组展开成集合。然后,在 EXISTS 子查询中,将这些集合内部连接到公共元素上。

SELECT *
       FROM some_table
       WHERE EXISTS (SELECT *
                            FROM jsonb_array_elements(some_table.foo->'bar') t (v)
                                 INNER JOIN jsonb_array_elements('[1,2]'::jsonb) s (v)
                                            ON t.v = s.v);

db<>fiddle

我想你需要的是:

  • 从 foo 中提取 bar,
  • 将任何元素从 bars 映射到 JSON,
  • 将绑定值转换为 array
  • 将绑定值数组转换为 jsonb[]
  • 检查左 JSON 值的 any 是否包含右 JSON path/value 条目在顶层 (@>):
SomeTable.where("foo->'bar' @> ANY(ARRAY[?]::JSONB[])", [1, 2].map(&:to_json))