首页 > 解决方案 > 通知的计数器功能未按预期工作

问题描述

我有通知表(category_id,user_id,seen)和计数器表:notifications_counter(user_id,未读)

当用户有新通知时(它插入到通知表中,see = false),他在通知计数器表中的 guid 的未读值必须增加。当用户将通知标记为已见 (notifications.seen=true) 时,它必须递减。

如果用户将 1 个通知标记为已见,则此方法有效。但是,如果他标记了许多(按 category_id),notifications_counter.unread 递减,但不是应有的 - 值仍然大于应有的值(例如,它是 2000,用户将通知标记为 category_id 看到的(标记了 600 个通知)它可以变成1900(必须是1400))。

功能:

    CREATE OR REPLACE FUNCTION notifications.notify_seen_upd()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
  begin 
      if new.seen = true and old.seen = false then 
        update notifications.notifications_counter 
            set unread = 
                (select unread
                from notifications.notifications_counter 
                where notifications_counter.user_id = new.user_id) - 1
            where notifications_counter.user_id = new.user_id;
      end if;
      if new.seen = false and old.seen = true then
        update notifications.notifications_counter 
        set unread =
            (select unread
                from notifications.notifications_counter 
                where notifications_counter.user_id = new.user_id) + 1
            where notifications_counter.user_id = new.user_id;
      end if;
  return new;        
  end;
$function$
;

扳机 :

create trigger z_notifications_upd after
update
    on
    notifications.notifications for each row execute function notifications.notify_seen_upd();

我在触发之前尝试过,结果是一样的

调用触发器的脚本示例:

UPDATE notifications.notifications AS t SET seen = true
WHERE (t.user_id = '6a16ca48-c215-4e9f-9d0f-cb78a0915192' and t.category_id = 1)

什么会导致这个麻烦?

标签: sqlpostgresqlfunctiontriggersnotifications

解决方案


我将建议一种替代方法。不要试图保持一个总和,这比它的价值更麻烦。而是摆脱 notifications_counter 表。这也摆脱了状态变化的触发和相应的判断。现在创建一个 VIEW notifications_counter。您现在可以只计算看到与未看到提供相同和额外的信息,而工作量要少得多。见演示

create view notifications_counter as
   select user_id 
        , count(*) as total 
        , count(*) filter (where seen)  as read
        , count(*) filter (where not seen)  as unread
     from user_notifications 
    group by user_id ;   

它还有一个优点是您不必担心通知被删除。


推荐阅读