[英]How can I import a JSON file into PostgreSQL?
例如,我有一个文件customers.json
,它是一个对象数组(严格形成),它非常简单(没有嵌套对象),就像这样(重要的是:它已经包含 id):
[
{
"id": 23635,
"name": "Jerry Green",
"comment": "Imported from facebook."
},
{
"id": 23636,
"name": "John Wayne",
"comment": "Imported from facebook."
}
]
我想将它们全部导入到我的 postgres 数据库中的表customers
中。
当我应该将它作为 json 类型的列导入到表中时,我发现了一些非常困难的方法imported_json
和名为data
的列,其中列出了对象,然后使用 sql 获取这些值并将其插入到真实表中。
但是有没有一种简单的方法可以在不接触 sql 的情况下将 json 导入 postgres?
您可以将 JSON 输入到 SQL 语句中,该语句提取信息并将其插入到表中。 如果 JSON 属性与表列的名称完全相同,您可以执行以下操作:
with customer_json (doc) as (
values
('[
{
"id": 23635,
"name": "Jerry Green",
"comment": "Imported from facebook."
},
{
"id": 23636,
"name": "John Wayne",
"comment": "Imported from facebook."
}
]'::json)
)
insert into customer (id, name, comment)
select p.*
from customer_json l
cross join lateral json_populate_recordset(null::customer, doc) as p
on conflict (id) do update
set name = excluded.name,
comment = excluded.comment;
将插入新客户,更新现有客户。 “神奇”部分是json_populate_recordset(null::customer, doc)
,它生成 JSON 对象的关系表示。
以上假设表定义如下:
create table customer
(
id integer primary key,
name text not null,
comment text
);
如果数据以文件形式提供,您需要先将该文件放入数据库中的某个表中。 像这样的东西:
create unlogged table customer_import (doc json);
然后将文件上传到该表的单行中,例如使用psql
的\\copy
命令(或您的 SQL 客户端提供的任何内容):
\copy customer_import from 'customers.json' ....
然后就可以使用上面的语句了,只需要去掉CTE,使用staging table:
insert into customer (id, name, comment)
select p.*
from customer_import l
cross join lateral json_populate_recordset(null::customer, doc) as p
on conflict (id) do update
set name = excluded.name,
comment = excluded.comment;
事实证明,有一种简单的方法可以使用命令行 psql 工具将多行 JSON 对象导入 postgres 数据库中的 JSON 列,而无需将 JSON 显式嵌入到 SQL 语句中。 该技术记录在postgresql docs 中,但它有点隐藏。
诀窍是使用反引号将 JSON 加载到 psql 变量中。 例如,给定/tmp/test.json 中的多行 JSON 文件,例如:
{
"dog": "cat",
"frog": "frat"
}
我们可以使用以下 SQL 将其加载到临时表中:
sql> \set content `cat /tmp/test.json`
sql> create temp table t ( j jsonb );
sql> insert into t values (:'content');
sql> select * from t;
这给出了结果:
j
────────────────────────────────
{"dog": "cat", "frog": "frat"}
(1 row)
也可以直接对数据进行操作:
sql> select :'content'::jsonb -> 'dog';
?column?
──────────
"cat"
(1 row)
在幕后这只是嵌入SQL中的JSON,但它是一个很大整洁,让PSQL进行插值本身。
在接近大数据的情况下,从文件导入 json 的最有效方法似乎不是从文件导入单个 json 而是单列 csv:一行 json 的列表:
数据.json.csv:
{"id": 23635,"name": "Jerry Green","comment": "Imported from facebook."}
{"id": 23636,"name": "John Wayne","comment": "Imported from facebook."}
然后,在 psql 下:
create table t ( j jsonb )
\copy t from 'd:\path\data.json.csv'
每个 json(行)一条记录将被添加到 t 表中。
"\\copy from" 导入是为 csv 进行的,因此逐行加载数据。 因此,每行读取一个 json 而不是稍后拆分的单个 json 数组,将不会使用任何中间表。
如果您的输入 json 文件太大,您将不太可能达到最大输入行大小限制。
因此,我会首先将您的输入转换为单列 csv,然后使用复制命令将其导入。
如果您想从命令行执行此操作...
注意:这不是您问题的直接答案,因为这需要您将 JSON 转换为 SQL。 无论如何,您可能必须在转换时处理 JSON 'null'。 不过,您可以使用视图或物化视图使该问题不可见。
这是我用于将 JSON 导入 PostgreSQL (WSL Ubuntu) 的脚本,它基本上要求您在同一命令行中混合 psql 元命令和 SQL。 注意使用有点晦涩的脚本命令,它分配了一个伪 tty:
$ more update.sh
#!/bin/bash
wget <filename>.json
echo '\set content `cat $(ls -t <redacted>.json.* | head -1)` \\ delete from <table>; insert into <table> values(:'"'content'); refresh materialized view <view>; " | PGPASSWORD=<passwd> psql -h <host> -U <user> -d <database>
$
(从我在Shell 脚本的回答中复制以在文件中执行 pgsql 命令)
您可以使用spyql 。 运行以下命令将生成 INSERT 语句,您可以将这些语句通过管道传输到 psql:
$ jq -c .[] customers.json | spyql -Otable=customer "SELECT json->id, json->name, json->comment FROM json TO sql"
INSERT INTO "customer"("id","name","comment") VALUES (23635,'Jerry Green','Imported from facebook.'),(23636,'John Wayne','Imported from facebook.');
jq 用于将 json 数组转换为 json 行(每行 1 个 json 对象),然后 spyql 负责将 json 行转换为 INSERT 语句。
要将数据导入 PostgreSQL:
$ jq -c .[] customers.json | spyql -Otable=customer "SELECT json->id, json->name, json->comment FROM json TO sql" | psql -U your_user_name -h your_host your_database
免责声明:我是 spyql 的作者。
另一种选择是使用吊索。 请参阅此博客文章,其中介绍了将 JSON 文件加载到 PG 中。 您可以像这样简单地通过管道传输您的 json 文件:
$ export POSTGRES='postgresql://...'
$ sling conns list
+------------+------------------+-----------------+
| CONN NAME | CONN TYPE | SOURCE |
+------------+------------------+-----------------+
| POSTGRES | DB - PostgreSQL | env variable |
+------------+------------------+-----------------+
$ cat /tmp/records.json | sling run --tgt-conn POSTGRES --tgt-object public.records --mode full-refresh
11:09AM INF connecting to target database (postgres)
11:09AM INF reading from stream (stdin)
11:09AM INF writing to target database [mode: full-refresh]
11:09AM INF streaming data
11:09AM INF dropped table public.records
11:09AM INF created table public.records
11:09AM INF inserted 500 rows in 0 secs [1,556 r/s]
11:09AM INF execution succeeded
如果不存在,使用debug
模式将显示create table if not exists public.records ("data" jsonb)
。 如果您想展平 JSON,sling 也可以通过添加--src-options 'flatten: true'
选项来做到这一点:
$ cat /tmp/records.json | sling run --src-options 'flatten: true' --tgt-conn POSTGRES --tgt-object public.records --mode full-refresh
这种情况下的 DDL 类似于:
create table if not exists public.records ("_id" varchar(255),
"age" integer,
"balance" varchar(255),
"company__about" text,
"company__address" varchar(255),
"company__email" varchar(255),
"company__latitude" numeric,
"company__longitude" numeric,
"company__name" varchar(255),
"company__phone" varchar(255),
"company__registered" varchar(255),
"isactive" bool,
"name" varchar(255),
"picture" varchar(255),
"tags" jsonb)
仅供参考,我是 sling 的作者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.