POSTGRESQL 从给定的 JSON 数组中插入多行,使用插入的结果进行其他插入
POSTGRESQL Insert Multiple Rows from given JSON array, use results from insert to do other inserts
TL;DR
音乐流媒体应用程序 - 允许用户上传自己的文件。
文件将存储在 FileSet 中。
我想传入多个 FILE(文件记录数组)和一个 FILESET,然后插入到适当的 tables.
抱歉,如果这有点令人困惑 - 基本上我正在使用 3 tables:
文件table
CREATE TABLE file
(
-- Most tables should have a table_id & table_cuid
file_id BIGSERIAL NOT NULL ,
file_cuid VARCHAR NOT NULL,
-- This section is specific to this table
user_id BIGINT NOT NULL,
-- File fields
filename VARCHAR NOT NULL,
last_modified TIMESTAMP WITHOUT TIME ZONE NOT NULL,
size_in_bytes VARCHAR NOT NULL,
mime_type VARCHAR NOT NULL,
-- Most tables should also have timestamps
created_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
-- Constraints
PRIMARY KEY (file_id),
FOREIGN KEY (user_id) REFERENCES users (user_id),
CONSTRAINT file_cuid_unique UNIQUE (file_cuid)
)
文件集Table
CREATE TABLE fileset
(
-- Most tables should have a table_id & table_cuid
fileset_id BIGSERIAL NOT NULL ,
fileset_cuid VARCHAR NOT NULL,
user_id BIGINT NOT NULL,
-- Fileset fields TBD
created_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
-- Constraints
PRIMARY KEY (fileset_id),
FOREIGN KEY (user_id) REFERENCES users (user_id),
CONSTRAINT cuid_unique_fileset UNIQUE (fileset_cuid)
)
最后是 File_FileSet_Rel Table
CREATE TABLE file_fileset_rel
(
file_id BIGSERIAL NOT NULL,
fileset_id BIGSERIAL NOT NULL,
FOREIGN KEY (file_id) REFERENCES file (file_id),
FOREIGN KEY (fileset_id) REFERENCES fileset (fileset_id),
UNIQUE (file_id, fileset_id)
)
每首歌曲都会有一个与之关联的文件集,并且该文件集有 one/multiple 个文件关联。
下面的函数 (file_upload_process) 允许我将文件添加到 table(返回 file_id),以及将文件集添加到 table(返回 fileset_id),最后函数将这两个值插入到最终的 table file_fileset_rel
file_upload_process.sql
CREATE OR REPLACE FUNCTION file_upload_process(
_file_cuid VARCHAR,
_fileset_cuid VARCHAR,
_cognito_id VARCHAR,
_name VARCHAR,
_last_modified TIMESTAMP,
_size DECIMAL,
_type VARCHAR
)
RETURNS TABLE(
fileId BIGINT,
fileSetID BIGINT
)
AS $file_upload_process$
DECLARE
v_user_id BIGINT;
v_file_id BIGINT;
v_fileset_id BIGINT;
BEGIN
-- Create Song/ Update song
-- store user_id
v_user_id := (
SELECT * FROM get_user_id(_cognito_id)
);
-- --Insert In FILE table
v_file_id := (
SELECT *
FROM create_file(
_file_cuid,
v_user_id,
_name,
_last_modified,
_size,
_type
)
);
--Insert into fileset table
v_fileset_id := (
SELECT * FROM create_fileset(_fileset_cuid, v_user_id)
);
RETURN QUERY
INSERT INTO file_fileset_rel(file_id, fileset_id)
VALUES (
v_file_id,
v_fileset_id
)
RETURNING file_fileset_rel.file_id,
file_fileset_rel.fileset_id;
END;
$file_upload_process$ LANGUAGE PLPGSQL;
其中调用了以下函数:
create_file.sql
CREATE OR REPLACE FUNCTION create_file(
_file_cuid VARCHAR,
_user_id BIGINT,
_name VARCHAR,
_last_modified TIMESTAMP,
_size DECIMAL,
_type VARCHAR
)
RETURNS TABLE (
_file_id BIGINT
)
AS $create_file$
BEGIN
RETURN QUERY
-- Create Song/ Update song
INSERT INTO file(
file_cuid,
user_id,
filename,
last_modified,
size_in_bytes,
mime_type,
created_timestamp,
updated_timestamp
)
VALUES(
_file_cuid,
_user_id,
_name,
_last_modified,
_size,
_type,
now(),
now()
)
RETURNING "file".file_id;
END;
$create_file$ LANGUAGE PLPGSQL;
和 create_fileset 函数:
CREATE OR REPLACE FUNCTION create_fileset(
_fileset_cuid VARCHAR,
_user_id BIGINT
)
RETURNS TABLE (
_fileset_id BIGINT
)
AS $create_fileset$
BEGIN
-- Create Song/ Update song
RETURN QUERY
INSERT INTO fileset(
fileset_cuid,
user_id,
created_timestamp,
updated_timestamp
)
VALUES(
_fileset_cuid,
_user_id,
now(),
now()
)
RETURNING "fileset".fileset_id;
END;
$create_fileset$ LANGUAGE PLPGSQL;
我遇到的问题是这个功能只允许您一次添加 1 个文件,用户可以为 1 首歌曲(1 个文件集)上传 5-10 个文件,所以我需要一种循环遍历fileRecords 数组并将这些字段的值存储在 FILE table 列中 - 最后允许我将多条记录添加到 file_fileset_rel table.
如果有人有更简单的方法来完成所有这些,或者更重要的是,解决多对一插入的问题将是一个巨大的帮助。
编辑:
CURRENT 主体被发送到 lambda 的示例 - 在传递到 postgresql 函数之前
URL -> 文件集/{filesetCuid}/文件
body: {
"cognitoId" : "9dc766a0-c5c9-4455-932e-46c243c80266",
"fileRecord" : {
"fileCuid" : "someotherfilecuid23",
"name" : "file_name",
"last_modified" : "06/03/1995",
"size" : 530,
"type" : "mp3/audio"
}
}
最终目标 - 发送多个文件:
URL -> 文件集/{filesetCuid}/文件
body: {
"cognitoId" : "9dc766a0-c5c9-4455-932e-46c243c80266",
"fileRecords" : [{
"fileCuid" : "someotherfilecuid23",
"name" : "file_name",
"last_modified" : "06/03/1995",
"size" : 530,
"type" : "mp3/audio"
}, {...}, {...}]
}
您可以从 file_upload_process.sql
中的 this PostgREST issue. You could also use a LOOP
改编一个优雅的解决方案,它包装了您所有的函数调用。
前者更好,因为它是一个很好的一体化更新插入逻辑:
- 它依赖于目标 table 的定义(例如
DEFAULT
值是动态设置的)
- 您可以直接传递一个 JSON 数组(即您 可以 省略不需要的值)
- 您可以处理
UNIQUE
约束的冲突(并自动检索现有行的 id
!)
TL;DR 音乐流媒体应用程序 - 允许用户上传自己的文件。 文件将存储在 FileSet 中。 我想传入多个 FILE(文件记录数组)和一个 FILESET,然后插入到适当的 tables.
抱歉,如果这有点令人困惑 - 基本上我正在使用 3 tables:
文件table
CREATE TABLE file
(
-- Most tables should have a table_id & table_cuid
file_id BIGSERIAL NOT NULL ,
file_cuid VARCHAR NOT NULL,
-- This section is specific to this table
user_id BIGINT NOT NULL,
-- File fields
filename VARCHAR NOT NULL,
last_modified TIMESTAMP WITHOUT TIME ZONE NOT NULL,
size_in_bytes VARCHAR NOT NULL,
mime_type VARCHAR NOT NULL,
-- Most tables should also have timestamps
created_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
-- Constraints
PRIMARY KEY (file_id),
FOREIGN KEY (user_id) REFERENCES users (user_id),
CONSTRAINT file_cuid_unique UNIQUE (file_cuid)
)
文件集Table
CREATE TABLE fileset
(
-- Most tables should have a table_id & table_cuid
fileset_id BIGSERIAL NOT NULL ,
fileset_cuid VARCHAR NOT NULL,
user_id BIGINT NOT NULL,
-- Fileset fields TBD
created_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_timestamp TIMESTAMP WITHOUT TIME ZONE NOT NULL,
-- Constraints
PRIMARY KEY (fileset_id),
FOREIGN KEY (user_id) REFERENCES users (user_id),
CONSTRAINT cuid_unique_fileset UNIQUE (fileset_cuid)
)
最后是 File_FileSet_Rel Table
CREATE TABLE file_fileset_rel
(
file_id BIGSERIAL NOT NULL,
fileset_id BIGSERIAL NOT NULL,
FOREIGN KEY (file_id) REFERENCES file (file_id),
FOREIGN KEY (fileset_id) REFERENCES fileset (fileset_id),
UNIQUE (file_id, fileset_id)
)
每首歌曲都会有一个与之关联的文件集,并且该文件集有 one/multiple 个文件关联。
下面的函数 (file_upload_process) 允许我将文件添加到 table(返回 file_id),以及将文件集添加到 table(返回 fileset_id),最后函数将这两个值插入到最终的 table file_fileset_rel
file_upload_process.sql
CREATE OR REPLACE FUNCTION file_upload_process(
_file_cuid VARCHAR,
_fileset_cuid VARCHAR,
_cognito_id VARCHAR,
_name VARCHAR,
_last_modified TIMESTAMP,
_size DECIMAL,
_type VARCHAR
)
RETURNS TABLE(
fileId BIGINT,
fileSetID BIGINT
)
AS $file_upload_process$
DECLARE
v_user_id BIGINT;
v_file_id BIGINT;
v_fileset_id BIGINT;
BEGIN
-- Create Song/ Update song
-- store user_id
v_user_id := (
SELECT * FROM get_user_id(_cognito_id)
);
-- --Insert In FILE table
v_file_id := (
SELECT *
FROM create_file(
_file_cuid,
v_user_id,
_name,
_last_modified,
_size,
_type
)
);
--Insert into fileset table
v_fileset_id := (
SELECT * FROM create_fileset(_fileset_cuid, v_user_id)
);
RETURN QUERY
INSERT INTO file_fileset_rel(file_id, fileset_id)
VALUES (
v_file_id,
v_fileset_id
)
RETURNING file_fileset_rel.file_id,
file_fileset_rel.fileset_id;
END;
$file_upload_process$ LANGUAGE PLPGSQL;
其中调用了以下函数:
create_file.sql
CREATE OR REPLACE FUNCTION create_file(
_file_cuid VARCHAR,
_user_id BIGINT,
_name VARCHAR,
_last_modified TIMESTAMP,
_size DECIMAL,
_type VARCHAR
)
RETURNS TABLE (
_file_id BIGINT
)
AS $create_file$
BEGIN
RETURN QUERY
-- Create Song/ Update song
INSERT INTO file(
file_cuid,
user_id,
filename,
last_modified,
size_in_bytes,
mime_type,
created_timestamp,
updated_timestamp
)
VALUES(
_file_cuid,
_user_id,
_name,
_last_modified,
_size,
_type,
now(),
now()
)
RETURNING "file".file_id;
END;
$create_file$ LANGUAGE PLPGSQL;
和 create_fileset 函数:
CREATE OR REPLACE FUNCTION create_fileset(
_fileset_cuid VARCHAR,
_user_id BIGINT
)
RETURNS TABLE (
_fileset_id BIGINT
)
AS $create_fileset$
BEGIN
-- Create Song/ Update song
RETURN QUERY
INSERT INTO fileset(
fileset_cuid,
user_id,
created_timestamp,
updated_timestamp
)
VALUES(
_fileset_cuid,
_user_id,
now(),
now()
)
RETURNING "fileset".fileset_id;
END;
$create_fileset$ LANGUAGE PLPGSQL;
我遇到的问题是这个功能只允许您一次添加 1 个文件,用户可以为 1 首歌曲(1 个文件集)上传 5-10 个文件,所以我需要一种循环遍历fileRecords 数组并将这些字段的值存储在 FILE table 列中 - 最后允许我将多条记录添加到 file_fileset_rel table.
如果有人有更简单的方法来完成所有这些,或者更重要的是,解决多对一插入的问题将是一个巨大的帮助。
编辑: CURRENT 主体被发送到 lambda 的示例 - 在传递到 postgresql 函数之前 URL -> 文件集/{filesetCuid}/文件
body: {
"cognitoId" : "9dc766a0-c5c9-4455-932e-46c243c80266",
"fileRecord" : {
"fileCuid" : "someotherfilecuid23",
"name" : "file_name",
"last_modified" : "06/03/1995",
"size" : 530,
"type" : "mp3/audio"
}
}
最终目标 - 发送多个文件: URL -> 文件集/{filesetCuid}/文件
body: {
"cognitoId" : "9dc766a0-c5c9-4455-932e-46c243c80266",
"fileRecords" : [{
"fileCuid" : "someotherfilecuid23",
"name" : "file_name",
"last_modified" : "06/03/1995",
"size" : 530,
"type" : "mp3/audio"
}, {...}, {...}]
}
您可以从 file_upload_process.sql
中的 this PostgREST issue. You could also use a LOOP
改编一个优雅的解决方案,它包装了您所有的函数调用。
前者更好,因为它是一个很好的一体化更新插入逻辑:
- 它依赖于目标 table 的定义(例如
DEFAULT
值是动态设置的) - 您可以直接传递一个 JSON 数组(即您 可以 省略不需要的值)
- 您可以处理
UNIQUE
约束的冲突(并自动检索现有行的id
!)