оператор select в функции postgres, вызываемой внутри триггера

#postgresql #plpgsql #database-trigger

#postgresql #plpgsql #база данных-триггер

Вопрос:

Я пытаюсь разработать систему уведомлений для серверной части приложения / веб-сайта для социальных сетей. Сейчас я сосредоточен на обновлениях статуса. Что я собираюсь сделать, так это поместить триггер в таблицу postgres, связанную с обновлениями статуса, чтобы каждый раз, когда публикуется новое обновление статуса, в мой код отправлялось уведомление.

До сих пор я был в состоянии это сделать. Но дополнительная функция, которую я хотел бы реализовать, — это извлечение всех людей, которые подписаны на пользователя, опубликовавшего обновление статуса, чтобы я мог также отправить им уведомление о том, что человек, на которого они подписаны, опубликовал новое обновление статуса.

Конечно, это можно реализовать, сначала получив уведомление о новом обновлении статуса от postgres, извлекая идентификатор пользователя человека, который его опубликовал, и делая запрос к базе данных, чтобы выяснить, какие пользователи следуют за ними.

Но я подумал, что было бы эффективнее, если бы я не делал запрос, а вместо этого каждый раз, когда postgres хочет отправить мне уведомление о новом обновлении статуса, он также делает запрос, чтобы выяснить, какие пользователи следят за постером обновления статуса, и отправляет эту информацию вместе с уведомлениемдля нового обновления статуса.

Но я не могу понять, как я могу сделать запрос в функции postgres, который зависит от аргумента этой функции, а затем отправить результат этого запроса вместе с аргументом в качестве уведомления.

это то, что я пробовал:

 create table example (c1 text, c2 text);

create function notif() 
   returns trigger as 
$$ 
begin 
  perform pg_notify('event',row_to_json(new)::text); 
  return new; 
end; 
$$ language plpgsql;

create trigger trig after insert 
   on example 
   for each row execute procedure notif();
  

А затем я прослушиваю канал событий из своего кода и получаю вставленную строку. Но я хочу выполнить оператор select на основе новой строки в моей функции notif () и отправить результат с новой строкой в код прослушивания.

Я был бы признателен за любые разъяснения

Спасибо

Комментарии:

1. Я также был бы признателен за разъяснение: как работает уведомление (триггер? NOTIFY ?) Что вы подразумеваете под «отправкой результата запроса вместе с аргументами функции»? Вы имеете в виду «отправить вместе с результатом функции»? Видите ли, некоторый набросок кода был бы полезен.

2. Просто: упакуйте результат запроса в JSON. В чем именно проблема?

3. ну, я не знаю, как это сделать. Я ничего не могу найти в документации postgres, и я тоже ничего не смог найти через Google.

4. Кроме того, в кодах, которые я написал, я не определяю какую-либо новую переменную, и даже функция, которую я создаю, не имеет никаких аргументов. Но каким-то волшебным образом использование return new строки возвращается в уведомлении. Как я должен что-то добавить к этому? Как работают переменные в postgres? Все это кажется таким волшебным, и в документации ничего четко не объясняется.

5. Тогда вам следует задать разные вопросы, например: «как составить значение JSON из NEW и какой-либо результат запроса в триггерной функции?» Функции JSON хорошо документированы, как есть NEW . Как бы то ни было, вопрос неясен и / или слишком широк.

Ответ №1:

Что-то вроде этого?

 CREATE FUNCTION notif()
RETURNS TRIGGER AS $$
DECLARE
    data JSONB;
    result JSONB;
BEGIN
    SELECT json_agg(tmp)  -- requires Postgres9.3 
    INTO data
    FROM (
        -- your subquery goes here, for example:
        SELECT followers.following_user_id
        FROM followers
        WHERE followers.followed_user_id = NEW.user_id
    ) tmp;

    result := json_build_object('data', data, 'row', row_to_json(NEW));
    PERFORM pg_notify('event', result::TEXT);
    RETURN NEW;
END;
$$ language plpgsql;
  

Также из комментариев:

Но каким-то волшебным образом использование return new строки возвращается в уведомлении.

Вы неправильно понимаете вещи. Возврат и уведомление — это две разные вещи.

Прежде всего, давайте разберемся с возвратом. Для триггеров AFTER INSERT возвращаемое значение полностью игнорируется:

Возвращаемое значение триггера уровня строки, запущенного ПОСЛЕ или триггера уровня оператора, запущенного ДО или ПОСЛЕ, всегда игнорируется; с таким же успехом оно может быть null .

Возвращаемое значение имеет значение только для триггеров BEFORE. В этом случае вы можете изменить (или даже запретить) строку перед записью в таблицу. Смотрите это: https://www.postgresql.org/docs/9.2/plpgsql-trigger.html Это не имеет никакого отношения к уведомлениям.

Так что насчет уведомлений? Все, что вы получаете от уведомления, — это то, что вы передаете в качестве второго аргумента pg_notify .Все это довольно хорошо документировано: https://www.postgresql.org/docs/9.0/sql-notify.html

Комментарии:

1. Это здорово, спасибо. Только одно. Я хочу, чтобы как NEW, так и результат подзапроса находились внутри объекта json, который отправляет pg_notify. Как я могу закодировать их в одну переменную?