繁体   English   中英

如何将 JSON 文件导入 PostgreSQL?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM