使用 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_id
和 post_id
的行,则删除该行(即用户选择不喜欢之前喜欢的 post),
否则使用 post_id
和 user_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 来表示该行处于活动状态。
我建议您不要使用大小写混合的名称(就像您对约束所做的那样)。
我正在尝试为 post 创建一个 "Like" 功能。
在我的网络应用程序中,我有一个 table 用户和一个 posts。我创建了一个名为 Like_posts
的新 table,我在其中保存哪个用户喜欢哪个 post。
一个核心约束,每个用户只能post点赞一次。如果用户点击 he/she 已经喜欢的 post 的赞按钮,那么它将 toggle/remove 赞状态。
基本逻辑是:
如果用户点击喜欢并且
如果 like_posts
已经包含带有 user_id
和 post_id
的行,则删除该行(即用户选择不喜欢之前喜欢的 post),
否则使用 post_id
和 user_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 来表示该行处于活动状态。
我建议您不要使用大小写混合的名称(就像您对约束所做的那样)。