Какой оператор postgres следует использовать для сравнения массивов / целых чисел с массивами? - PullRequest
2 голосов
/ 11 мая 2019

У меня есть модель Event со столбцом jsonb для visibility_constraints. Запись обычно содержит четыре массива included_users, included_teams, excluded_users и excluded_teams. Event имеет видимость общего или частного.

Также созданы индексы для четырех массивов:

CREATE INDEX visibility_constraints_included_teams_on_events ON events USING GIN ((visibility_constraints->'included_teams'))

Создать событие

Event.create(summary: 'Test', visibility_constraints: { included_users: [1, 2, 3], included_teams: [1, 2], excluded_users: [4, 5, 6], excluded_teams: [3, 4] })
=> #<Event:0x00007fc99d8f9670
 id: 1,
 summary: "Test",
 starts_at: Sat, 11 May 2019 21:00:00 CEST +02:00,
 ends_at: Sat, 11 May 2019 22:00:00 CEST +02:00,
 visibility: "vis_private",
 visibility_constraints: {"included_users"=>[1, 2, 3], "included_teams"=>[1, 2], "excluded_users"=>[4, 5, 6], "excluded_teams"=>[3, 4]}>

Теперь я пытаюсь получить события, где current_user.id находится в included_users

Event.where("visibility_constraints -> 'included_users' ? :user_id", user_id: current_user.id.to_json)

(0.4ms)  SELECT "events".* FROM "events" WHERE (visibility_constraints -> 'included_users' ? '1')

… или где current_user.team_ids находится в included_teams.

Event.where("visibility_constraints -> 'included_teams' ? :team_ids", team_ids: current_user.team_ids.to_json)

 (0.5ms)  SELECT "events".* FROM "events" WHERE (visibility_constraints -> 'included_teams' ? '[3,5,1]')

Эти запросы всегда ничего не возвращают, поэтому мне интересно, что я могу сделать неправильно. Я что-то где-то забыл? Использовать другой оператор (ну, я пытался, но ничего не изменилось)?

Спасибо за вашу помощь!


EDIT

\ d public.events

+------------------------+-----------------------------+------------------------------------------------------+
| Column                 | Type                        | Modifiers                                            |
|------------------------+-----------------------------+------------------------------------------------------|
| id                     | bigint                      |  not null default nextval('events_id_seq'::regclass) |
| summary                | character varying           |                                                      |
| description            | text                        |                                                      |
| starts_at              | timestamp without time zone |                                                      |
| ends_at                | timestamp without time zone |                                                      |
| allday                 | boolean                     |                                                      |
| created_at             | timestamp without time zone |  not null                                            |
| updated_at             | timestamp without time zone |  not null                                            |
| aasm_state             | character varying           |                                                      |
| visibility             | visibility                  |  default 'vis_private'::visibility                   |
| stage_id               | bigint                      |                                                      |
| visibility_constraints | jsonb                       |  not null default '{}'::jsonb                        |
+------------------------+-----------------------------+------------------------------------------------------+
Indexes:
    "events_pkey" PRIMARY KEY, btree (id)
    "index_events_on_stage_id" btree (stage_id)
    "index_events_on_visibility_constraints" gin (visibility_constraints)
    "visibility_constraints_included_teams_on_events" gin ((visibility_constraints -> 'included_teams'::text))
    "visibility_constraints_included_users_on_events" gin ((visibility_constraints -> 'included_users'::text))
Foreign-key constraints:
    "fk_rails_cb489a462e" FOREIGN KEY (stage_id) REFERENCES stages(id)
Referenced by:
    TABLE "availabilities" CONSTRAINT "fk_rails_6d29de0e36" FOREIGN KEY (event_id) REFERENCES events(id)
    TABLE "assignments" CONSTRAINT "fk_rails_6a5328b71e" FOREIGN KEY (event_id) REFERENCES events(id)
    TABLE "resource_allocations" CONSTRAINT "fk_rails_2958f606d4" FOREIGN KEY (event_id) REFERENCES events(id)

Time: 0.048s

РЕДАКТИРОВАТЬ 2

SELECT * FROM events

+------+-----------+----------------------------+----------------------------+-----------------------------------------------------------------------------------------------------------------+
| id   | summary   | created_at                 | updated_at                 | visibility_constraints                                                                                          |
|------+-----------+----------------------------+----------------------------+-----------------------------------------------------------------------------------------------------------------|
| 3    | event 3   | 2019-05-15 00:24:50.699237 | 2019-05-15 00:24:50.699237 | "{\"included_users\":[1,2,3],\"included_teams\":[1,2,3],\"excluded_users\":[4,5,6],\"excluded_teams\":[4,5,6]}" |
| 4    | event 4   | 2019-05-15 00:24:55.487215 | 2019-05-15 00:24:55.487215 | "{\"included_users\":[1,2,3],\"included_teams\":[1,2,3],\"excluded_users\":[4,5,6],\"excluded_teams\":[4,5,6]}" |
| 5    | event 5   | 2019-05-15 00:26:15.872433 | 2019-05-15 00:26:15.872433 | "{\"included_users\":[2,3],\"included_teams\":[],\"excluded_users\":[],\"excluded_teams\":[]}"                  |
+------+-----------+----------------------------+----------------------------+-----------------------------------------------------------------------------------------------------------------+

Ответы [ 2 ]

0 голосов
/ 11 мая 2019

Привязка user_id к ключевому аргументу мало поможет в вашем случае. Что вы можете сделать, это обернуть его в [] и преобразовать в JSON.

Используя оператор «contains», вы можете проверить, содержит ли левое значение JSON правильные записи пути / значения JSON на верхнем уровне? :

Event.where(
  'visibility_constraints @> ?', { included_users: [current_user.id] }.to_json
)

, который генерирует:

SELECT "events".*
FROM "events"
WHERE (visibility_constraints @> '{"included_users":[<current_user_id_as_integer>]}')
0 голосов
/ 11 мая 2019

Я не знаю рубина, но есть два основных способа сделать это.

Предпочтительным способом является использование оператора удержания @>, например ::

SELECT *
FROM (
    SELECT '{"included_users":[1, 2, 3]}'::jsonb AS visibility_constraints
) AS events
WHERE events.visibility_constraints->'included_users' @> '[2]'::jsonb;

Если это невозможно с использованием структуры выбора, вот альтернатива:

SELECT events.*
FROM
    (
        SELECT '{"included_users":[1, 2, 3]}'::jsonb AS visibility_constraints
    ) AS events,
    -- lateral function correlated to entries of "events"
    jsonb_array_elements(events.visibility_constraints->'included_users') AS included_users
WHERE included_users::integer = 2;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...