#sql #node.js #json #postgresql #sequelize.js
#sql #node.js #json #postgresql #sequelize.js
Вопрос:
У меня есть большой файл данных в формате json, который я хочу поместить в свою базу данных. Некоторые объекты являются дубликатами, поэтому я хочу обновить данные на случай, если строка уже есть в базе данных. Вот мой код:
const FILE_PATH = path.join(__dirname, "../../files/apps.json");
const columns = [
"name",
"description",
"ext_id"
];
const myFile = fs.readFileSync(FILE_PATH, { encoding: "utf-8" });
const appData = await models.sequelize.query(
`
INSERT INTO data (${columns.join(", ")})
SELECT ${columns.join(", ")}
FROM (:path)
ON CONFLICT (ext_id)
DO UPDATE SET
${columns.map(col => `${col} = EXCLUDED.${col}`).join(", ")}
RETURNING ext_id;
`,
{ replacements: { path: FILE_PATH } }
);
Как вы можете видеть, я хочу прочитать файл напрямую и поместить его в базу данных. Я использую средство отображения под названием sequelize , но в данном случае использую необработанный запрос. Моя непосредственная проблема заключается в том, что я получаю эту ошибку:
syntax error at or near "'/home/blub/filePath'"
Я действительно не знаю, как мне следует указывать путь. Я попытался проанализировать его напрямую, но затем программа пожаловалась на /. Любая помощь здесь? Кроме того, я также не уверен, является ли запрос синтаксически правильным.
Ответ №1:
Вот решение, использующее CTE postgres.
Версии:
"sequelize": "^5.21.3"
- postgres: 9.6
apps.json
:
[
{
"name": "app-a",
"description": "app a desc",
"ext_id": 1
},
{
"name": "app-b",
"description": "app b desc",
"ext_id": 2
},
{
"name": "app-c",
"description": "app c desc",
"ext_id": 3
}
]
index.ts
:
import { sequelize } from '../../db';
import { Model, DataTypes, QueryTypes } from 'sequelize';
import fs from 'fs';
import path from 'path';
class Data extends Model {}
Data.init(
{
name: DataTypes.STRING,
description: DataTypes.STRING,
ext_id: {
type: DataTypes.INTEGER,
unique: true,
},
},
{ sequelize, tableName: 'data' },
);
(async function test() {
try {
await sequelize.sync({ force: true });
const FILE_PATH = path.join(__dirname, './apps.json');
const columns = ['name', 'description', 'ext_id'];
const myFile = fs.readFileSync(FILE_PATH, { encoding: 'utf-8' });
const appData = await sequelize.query(
`
with app_json(doc) as (
values ('${myFile}'::json)
)
insert into data (${columns.join(', ')})
select ${columns.join(', ')}
from app_json l
cross join lateral json_populate_recordset(null::data, doc) as p
on conflict (ext_id) do update
set ${columns.map((col) => `${col} = EXCLUDED.${col}`).join(', ')}
returning ext_id;
`,
{ type: QueryTypes.INSERT },
);
console.log(appData);
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
Результат выполнения:
Executing (default): DROP TABLE IF EXISTS "data" CASCADE;
Executing (default): DROP TABLE IF EXISTS "data" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "data" ("id" SERIAL , "name" VARCHAR(255), "description" VARCHAR(255), "ext_id" INTEGER UNIQUE, PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'data' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): with app_json(doc) as (
values ('[
{
"name": "app-a",
"description": "app a desc",
"ext_id": 1
},
{
"name": "app-b",
"description": "app b desc",
"ext_id": 2
},
{
"name": "app-c",
"description": "app c desc",
"ext_id": 3
}
]'::json)
)
insert into data (name, description, ext_id)
select name, description, ext_id
from app_json l
cross join lateral json_populate_recordset(null::data, doc) as p
on conflict (ext_id) do update
set name = EXCLUDED.name, description = EXCLUDED.description, ext_id = EXCLUDED.ext_id
returning ext_id;
[ [ { ext_id: 1 }, { ext_id: 2 }, { ext_id: 3 } ], 3 ]
Проверьте записи данных в базе данных:
id name description ext_id
1 app-a app a desc 1
2 app-b app b desc 2
3 app-c app c desc 3
Комментарии:
1. Спасибо за вашу помощь. Я уже нашел обходной путь, но ваш ответ очень ценится.