如何使用 Slonik 将多条记录插入到我的 postgres 数据库中?
How do I insert multiple records into my postgres database using Slonik?
我是一名前端开发人员,这是我第一次使用 Slonik 和 postgresql。
我想知道如何通过使用函数参数插入数据(硬编码)使此查询动态化:
const addMany = async (connection = slonik) => {
const useResult = await connection.query(sql`
INSERT into
users (username, email)
VALUES
('amite', 'amite@gmail.com'),
('nilesh', 'nil@gmail.com'),
('nikhil', 'nik@gmail.com')
RETURNING *;
`);
return useResult;
};
我需要使用字符串连接来创建元组吗?我很困惑
('amite', 'amite@gmail.com'),
('nilesh', 'nil@gmail.com'),
('nikhil', 'nik@gmail.com')
目前我尝试过的是:
const addManyUsers = async(connection = slonik) => {
const keys = [
'username', 'email'
];
const values = [
['nilesh', 'bailey'],
['nilesh@gmail.com', 'bailey@gmail.com']
]
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, sql`, `)})
RETURNING *
`
const records = await connection.query(query)
return records
}
当我 运行 出现这个错误时:
(node:5975) UnhandledPromiseRejectionWarning: Error: **Column types length must match tuple member length.**
at Object.createUnnestSqlFragment (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/sqlFragmentFactories/createUnnestSqlFragment.js:29:19)
at Object.createSqlTokenSqlFragment (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/factories/createSqlTokenSqlFragment.js:27:39)
at sql (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/factories/createSqlTag.js:39:65)
at addManyUsers (/Users/shreekant/Documents/code/node/postgres-starter/app/models/db.js:58:20)
at Object.<anonymous> (/Users/shreekant/Documents/code/node/postgres-starter/app/models/db.js:72:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47
(Use `node --trace-warnings ...` to show where the warning was created)
(node:5975) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:5975) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
这就是我的 table 结构的样子。我正在使用 `varchar(50)
我做错了什么?
@RaghavGarg。这是根据您的建议更新后的代码:
const keys = [
'username',
'email',
];
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = ['varchar', 'varchar'];
const main = async(connection = slonik) => {
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
try {
const results = await connection.query(query)
console.log(results);
return results
} catch (error) {
console.error(error);
}
}
main()
上面的查询扩展为:
{
sql: '\n' +
'INSERT INTO users\n' +
' ("username", "email")\n' +
'VALUES\n' +
' (unnest(::"varchar(50)"[], ::"varchar(50)"[]))\n' +
'RETURNING *\n',
type: 'SLONIK_TOKEN_SQL',
values: [
[ 'nilesh', 'bailey' ],
[ 'nilesh@gmail.com', 'bailey@gmail.com' ]
]
}
我现在得到的错误是:
error: type "varchar(50)[]" does not exist
at Parser.parseErrorMessage (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:278:15)
at Parser.handlePacket (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:126:29)
at Parser.parse (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:39:38)
at Socket.<anonymous> (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/index.js:10:42)
at Socket.emit (events.js:315:20)
at Socket.EventEmitter.emit (domain.js:486:12)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:284:9)
at Socket.Readable.push (_stream_readable.js:223:10)
at TCP.onStreamRead (internal/stream_base_commons.js:188:23) {
length: 100,
severity: 'ERROR',
code: '42704',
detail: undefined,
hint: undefined,
position: '81',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_type.c',
line: '274',
routine: 'typenameType',
notices: []
}
传递给方法 sql.unnest
的参数存在问题。它以数据数组作为第一个参数,类型数组作为第二个参数。
错误也是这么说的
Column types length must match tuple member length
因此您的代码应该更改为
const values_types = ['text', 'text'];
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
的文档
(
tuples: $ReadOnlyArray<$ReadOnlyArray>,
columnTypes: $ReadOnlyArray
): UnnestSqlTokenType;
此外,您应该考虑将代码包装在 try/catch
块中并正确处理错误。
(node:5975) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
更新 1
变量 value_types
是一个数组,其中包含您使用查询插入的每一列的类型。
所以 value_types
应该总是与 values
的任何成员具有相同数量的元素
values[i].length === values_types.length
并且类型数组中的每个索引都应该对应于成员的正确值。所以
// for
values_types = ["text", "text", "int4"]
// any values[i] should be
values[i] = ["nilesh", "nilesh@gmail.com", 123]
我错过了一件事,values
也是错误的,每个成员都应该是一个有效的记录,即一个记录的所有列值。
变量应如下所示
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
所以你的最终代码看起来像这样
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = ['text', 'text'];
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
这终于奏效了。我需要使用 SELECT * FROM
而不是 VALUES
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
SELECT * FROM
${sql.unnest(values, values_types)}
RETURNING *
`
这是整个函数:
const keys = [
'username',
'email',
];
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = [`varchar`,`varchar`];
const main = async(connection = slonik) => {
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
SELECT * FROM
${sql.unnest(values, values_types)}
RETURNING *
`
try {
const results = await connection.query(query)
console.log(results);
return results
} catch (error) {
console.error(error);
}
}
main()
查询现在扩展为:
{
sql: '\n' +
'INSERT INTO users\n' +
' ("username", "email")\n' +
'SELECT * FROM\n' +
' unnest(::"varchar"[], ::"varchar"[])\n' +
'RETURNING *\n',
type: 'SLONIK_TOKEN_SQL',
values: [
[ 'nilesh', 'bailey' ],
[ 'nilesh@gmail.com', 'bailey@gmail.com' ]
]
}
我是一名前端开发人员,这是我第一次使用 Slonik 和 postgresql。
我想知道如何通过使用函数参数插入数据(硬编码)使此查询动态化:
const addMany = async (connection = slonik) => {
const useResult = await connection.query(sql`
INSERT into
users (username, email)
VALUES
('amite', 'amite@gmail.com'),
('nilesh', 'nil@gmail.com'),
('nikhil', 'nik@gmail.com')
RETURNING *;
`);
return useResult;
};
我需要使用字符串连接来创建元组吗?我很困惑
('amite', 'amite@gmail.com'),
('nilesh', 'nil@gmail.com'),
('nikhil', 'nik@gmail.com')
目前我尝试过的是:
const addManyUsers = async(connection = slonik) => {
const keys = [
'username', 'email'
];
const values = [
['nilesh', 'bailey'],
['nilesh@gmail.com', 'bailey@gmail.com']
]
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, sql`, `)})
RETURNING *
`
const records = await connection.query(query)
return records
}
当我 运行 出现这个错误时:
(node:5975) UnhandledPromiseRejectionWarning: Error: **Column types length must match tuple member length.**
at Object.createUnnestSqlFragment (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/sqlFragmentFactories/createUnnestSqlFragment.js:29:19)
at Object.createSqlTokenSqlFragment (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/factories/createSqlTokenSqlFragment.js:27:39)
at sql (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/slonik/dist/factories/createSqlTag.js:39:65)
at addManyUsers (/Users/shreekant/Documents/code/node/postgres-starter/app/models/db.js:58:20)
at Object.<anonymous> (/Users/shreekant/Documents/code/node/postgres-starter/app/models/db.js:72:1)
at Module._compile (internal/modules/cjs/loader.js:1063:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:72:12)
at internal/main/run_main_module.js:17:47
(Use `node --trace-warnings ...` to show where the warning was created)
(node:5975) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:5975) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
这就是我的 table 结构的样子。我正在使用 `varchar(50)
我做错了什么?
@RaghavGarg。这是根据您的建议更新后的代码:
const keys = [
'username',
'email',
];
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = ['varchar', 'varchar'];
const main = async(connection = slonik) => {
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
try {
const results = await connection.query(query)
console.log(results);
return results
} catch (error) {
console.error(error);
}
}
main()
上面的查询扩展为:
{
sql: '\n' +
'INSERT INTO users\n' +
' ("username", "email")\n' +
'VALUES\n' +
' (unnest(::"varchar(50)"[], ::"varchar(50)"[]))\n' +
'RETURNING *\n',
type: 'SLONIK_TOKEN_SQL',
values: [
[ 'nilesh', 'bailey' ],
[ 'nilesh@gmail.com', 'bailey@gmail.com' ]
]
}
我现在得到的错误是:
error: type "varchar(50)[]" does not exist
at Parser.parseErrorMessage (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:278:15)
at Parser.handlePacket (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:126:29)
at Parser.parse (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/parser.js:39:38)
at Socket.<anonymous> (/Users/shreekant/Documents/code/node/postgres-starter/node_modules/pg-protocol/dist/index.js:10:42)
at Socket.emit (events.js:315:20)
at Socket.EventEmitter.emit (domain.js:486:12)
at addChunk (_stream_readable.js:309:12)
at readableAddChunk (_stream_readable.js:284:9)
at Socket.Readable.push (_stream_readable.js:223:10)
at TCP.onStreamRead (internal/stream_base_commons.js:188:23) {
length: 100,
severity: 'ERROR',
code: '42704',
detail: undefined,
hint: undefined,
position: '81',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_type.c',
line: '274',
routine: 'typenameType',
notices: []
}
传递给方法 sql.unnest
的参数存在问题。它以数据数组作为第一个参数,类型数组作为第二个参数。
错误也是这么说的
Column types length must match tuple member length
因此您的代码应该更改为
const values_types = ['text', 'text'];
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
的文档
( tuples: $ReadOnlyArray<$ReadOnlyArray>, columnTypes: $ReadOnlyArray ): UnnestSqlTokenType;
此外,您应该考虑将代码包装在 try/catch
块中并正确处理错误。
(node:5975) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
更新 1
变量 value_types
是一个数组,其中包含您使用查询插入的每一列的类型。
所以 value_types
应该总是与 values
values[i].length === values_types.length
并且类型数组中的每个索引都应该对应于成员的正确值。所以
// for
values_types = ["text", "text", "int4"]
// any values[i] should be
values[i] = ["nilesh", "nilesh@gmail.com", 123]
我错过了一件事,values
也是错误的,每个成员都应该是一个有效的记录,即一个记录的所有列值。
变量应如下所示
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
所以你的最终代码看起来像这样
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = ['text', 'text'];
const query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
VALUES
(${sql.unnest(values, values_types)})
RETURNING *
`
这终于奏效了。我需要使用 SELECT * FROM
而不是 VALUES
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
SELECT * FROM
${sql.unnest(values, values_types)}
RETURNING *
`
这是整个函数:
const keys = [
'username',
'email',
];
const identifiers = keys.map((key) => {
return sql.identifier([key]);
});
const values = [
['nilesh', 'nilesh@gmail.com'], // single full record
['bailey', 'bailey@gmail.com'], // single full record
]
const values_types = [`varchar`,`varchar`];
const main = async(connection = slonik) => {
let query = sql`
INSERT INTO users
(${sql.join(identifiers, sql`, `)})
SELECT * FROM
${sql.unnest(values, values_types)}
RETURNING *
`
try {
const results = await connection.query(query)
console.log(results);
return results
} catch (error) {
console.error(error);
}
}
main()
查询现在扩展为:
{
sql: '\n' +
'INSERT INTO users\n' +
' ("username", "email")\n' +
'SELECT * FROM\n' +
' unnest(::"varchar"[], ::"varchar"[])\n' +
'RETURNING *\n',
type: 'SLONIK_TOKEN_SQL',
values: [
[ 'nilesh', 'bailey' ],
[ 'nilesh@gmail.com', 'bailey@gmail.com' ]
]
}