簡體   English   中英

如何使用 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.

這就是我的表結構的樣子。 我正在使用 `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($1::"varchar(50)"[], $2::"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的參數存在問題。 它將數據數組作為第一個參數,將類型數組作為第二個參數。

這也是錯誤所說的

列類型長度必須匹配元組成員長度

所以你的代碼應該變成類似的東西

const values_types = ['text', 'text'];

const query = sql`
  INSERT INTO users
    (${sql.join(identifiers, sql`, `)})
  VALUES
    (${sql.unnest(values, values_types)})
  RETURNING *
`

sql.unnest文檔

( 元組: $ReadOnlyArray<$ReadOnlyArray>, columnTypes: $ReadOnlyArray ): UnnestSqlTokenType;


此外,您應該考慮將代碼包裝在try/catch塊中並正確處理錯誤。

(節點:5975)[DEP0018] 棄用警告:不推薦使用未處理的承諾拒絕。 將來,未處理的承諾拒絕將使用非零退出代碼終止 Node.js 進程。


更新 1

變量value_types是一個數組,其中包含您使用查詢插入的每一列的類型。

因此value_types應該始終具有與values的任何成員相同數量的元素

values[i].length === values_types.length

並且 types 數組中的每個索引都應對應於成員的正確值。 所以

// 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($1::"varchar"[], $2::"varchar"[])\n' +
    'RETURNING *\n',
  type: 'SLONIK_TOKEN_SQL',
  values: [
    [ 'nilesh', 'bailey' ],
    [ 'nilesh@gmail.com', 'bailey@gmail.com' ]
  ]
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM