使用 PG upsert 为 post 上的 "like" 操作创建切换

Using PG upsert for creating a toggle for "like" action on post

我正在尝试为 post 创建一个 "Like" 功能。 在我的网络应用程序中,我有一个 table 用户和一个 posts。我创建了一个名为 Like_posts 的新 table,我在其中保存哪个用户喜欢哪个 post。

一个核心约束,每个用户只能post点赞一次。如果用户点击 he/she 已经喜欢的 post 的赞按钮,那么它将 toggle/remove 赞状态。

基本逻辑是:

如果用户点击喜欢并且
如果 like_posts 已经包含带有 user_idpost_id 的行,则删除该行(即用户选择不喜欢之前喜欢的 post), 否则使用 post_iduser_id 添加一个新行。

目前我正在触发 2 个单独的查询,首先检查该行是否存在,然后我的应用程序决定是否应该插入或删除。考虑到我希望 "like" 成为最常用的改变数据库数据的功能之一,我真的想在一个查询中完成它。

我知道我可以通过数组(liked_by --> user_id in posts table)但我不想走那条路.使用不同数据展开和重新创建数组的性能不是很好,我真的不喜欢在 PG 中使用数组或 jsonb(不喜欢 API)。

我想使用 upsert 之类的东西,但据我所知,我只能在需要 "On conflict (both col1 and col2)".

时执行 "On Conflict (single column)"

我有哪些选择?在我的数据库中设计 "Like" 按钮切换的好方法是什么?

根据@Laurenz Albe 的出色建议,我改进了该方法。 我现在对 2 列有一个独特的约束:

CREATE TABLE LIKE_POSTS (
    POST_ID TEXT NOT NULL,
    USER_ID TEXT NOT NULL,
    CREATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UPDATED_AT TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    DELETED_AT TIMESTAMP,
    CONSTRAINT "Unique_user_and_post_combo" PRIMARY KEY (POST_ID, USER_ID)
);
insert into like_posts (post_id, user_id) values (1,1);

我仍然不确定如何执行删除操作。像;

insert into like_posts (post_id, user_id) values (1,1) 
returning "ON"
ON CONFLICT ON CONSTRAINT Unique_user_and_post_combo
DO DELETE RETURNING "OFF";

现在你有了一个主键约束,切换标志应该很简单:

INSERT INTO like_posts (post_id, user_id, deleted_at)
   VALUES (1, 1, NULL) 
ON CONFLICT ON CONSTRAINT "Unique_user_and_post_combo"
DO UPDATE SET deleted_at = CASE WHEN deleted_at IS NULL
                                THEN current_timestamp
                           END;

这假定您在 deleted_at 中使用 NULL 来表示该行处于活动状态。

我建议您不要使用大小写混合的名称(就像您对约束所做的那样)。