如何将 JSON 文件转换为 SQLite 数据库
How to convert a JSON file to an SQLite database
如果我有一些示例数据,如何将其放入 SQLite(最好是全自动的)?
{"uri":"/","user_agent":"example1"}
{"uri":"/foobar","user_agent":"example1"}
{"uri":"/","user_agent":"example2"}
{"uri":"/foobar","user_agent":"example3"}
我发现最简单的方法是使用 jq 和 CSV 作为中间格式。
编辑:
正如所指出的(感谢 @Leo), the original question did show newline delimited JSON objects, which each on their own conform to rfc4627,但不是所有的格式都在一起。
jq 可以处理 objects 的单个 JSON 数组,尽管通过使用 jq '.[]' <input.json >preprocessed.json
预处理文件,方法与此大致相同。
如果您碰巧正在处理 JSON 文本序列 (rfc7464),幸运的是 jq 也通过 --seq
参数支持了您。
编辑 2:
换行分隔 JSON 和 JSON 文本序列都有一个重要的优点;它们将内存需求降低到 O(1),这意味着您的总内存需求仅取决于您最长的输入行,而将整个输入放在一个数组中需要您的解析器可以处理后期错误(即在第一个 100k 之后元素有语法错误),据我所知通常不是这种情况,或者它必须解析整个文件两次(首先验证语法,然后解析,在丢弃先前元素的过程中,就像 jq --stream
) 这在我看来也很少发生,或者它会尝试一次解析整个输入并一步 return 结果(想想接收一个 Python dict 其中包含整个你说的 50G 输入数据加上开销)通常是内存支持的,因此你的内存占用量增加了你的总数据大小。
编辑 3:
如果遇到任何障碍,请尝试使用 keys_unsorted 而不是 keys。
我自己还没有测试过(我假设我的列已经排序),但是 @Kyle Barron reports that this was needed.
获取 CSV
首先将数据写入文件。
我将在这里假设 data.json。
然后构造 header 使用 jq
:
% head -1 data.json | jq -r 'keys | @csv'
"uri","user_agent"
head -1
是因为我们只想要一行。
jq
的 -r
使输出成为纯字符串而不是 JSON-String 包装 CSV。
然后我们调用内部函数 keys
将输入的键作为数组获取。
我们将其发送到 @csv
格式化程序,后者以引用的 CSV 格式向我们输出一个带有 header 的字符串。
然后我们需要构建数据。
% jq -r '[.[]] | @csv' < data.json
"/","example1"
"/foobar","example1"
"/","example2"
"/foobar","example3"
我们现在获取整个输入并使用 .[]
解构关联数组(映射),然后将其放回简单数组 […]
。
这基本上将我们的字典转换为键数组。
发送到 @csv
格式化程序,我们再次获得一些 CSV。
将所有内容放在一起,我们得到一个 one-liner,其形式为:
% (head -1 data.json | jq -r 'keys | @csv' && jq -r '[.[]] | @csv' < data.json) > data.csv
如果您需要即时转换数据,即没有文件,试试这个:
% cat data.json | (read -r first && jq -r '(keys | @csv),( [.[]] | @csv)' <<<"${first}" && jq -r '[.[]] | @csv')
正在将其加载到 SQLite 中
打开 SQLite 数据库:
sqlite3 somedb.sqlite
现在在交互式 shell 中执行以下操作(假设您将 CSV 写入 data.csv 并希望在 table 中调用my_table
):
.mode csv
.import data.csv my_table
现在关闭 shell 并再次打开它以获得干净的环境。
您现在可以轻松 SELECT
从数据库中进行任何您想做的事情。
综合起来
asciinema 录音:
sqlitebiter 似乎提供了 python 解决方案:
将 CSV/Excel/HTML/JSON/LTSV/Markdown/SQLite/TSV/Google-Sheets 转换为 SQLite 数据库文件的 CLI 工具。 http://sqlitebiter.rtfd.io/
文档:
http://sqlitebiter.readthedocs.io/en/latest/
项目:
https://github.com/thombashi/sqlitebiter
- 上次更新大约 3 个月前
- 上一期大约 1 个月前关闭,none 打开
- 今天注意到,2018-03-14
无需 CSV 或第 3 方工具 的方法是使用 sqlite3
CLI 工具中提供的 JSON1
extension of SQLite combined with the readfile
extension。
如果输入文件是格式正确的 JSON 文件,例如作为数组给出的示例:
[
{"uri":"/","user_agent":"example1"},
{"uri":"/foobar","user_agent":"example1"},
{"uri":"/","user_agent":"example2"},
{"uri":"/foobar","user_agent":"example3"}
]
那么这个可以读入对应的my_table
table如下。使用 sqlite3 CLI 打开 SQLite 数据库文件 my_db.db
:
sqlite3 my_db.db
然后创建 my_table
使用:
CREATE TABLE my_table(uri TEXT, user_agent TEXT);
最后,my_data.json
中的JSON数据可以用CLI命令插入到table中:
INSERT INTO my_table SELECT
json_extract(value, '$.uri'),
json_extract(value, '$.user_agent')
FROM json_each(readfile('my_data.json'));
除了总体上是一个“更直接”的解决方案外,它还具有处理 JSON NULL 值比 CSV 更一致的优势,否则 CSV 会将它们导入为空字符串。
如果初始 JSON 文件是换行符分隔的 JSON 元素,则可以先使用 jq
转换:
jq -s <my_data_raw.json >my_data.json
可能有一种方法可以使用 JSON1 在 SQLite 中直接执行此操作,但鉴于我已经在使用 jq
进行按摩,我没有继续这样做导入 SQLite 之前的数据。
您可以使用 spyql。
spyql 读取 json 文件(每行 1 个 json 对象)并生成 INSERT 语句,您可以通过管道将其导入 sqlite:
$ spyql -Otable=my_table "SELECT json->uri, json->user_agent FROM json TO sql" < sample3.json | sqlite3 my.db
这假设您已经在 sqlite 数据库 my.db
中创建了一个空的 table。
免责声明:我是spyql的作者。
如果我有一些示例数据,如何将其放入 SQLite(最好是全自动的)?
{"uri":"/","user_agent":"example1"}
{"uri":"/foobar","user_agent":"example1"}
{"uri":"/","user_agent":"example2"}
{"uri":"/foobar","user_agent":"example3"}
我发现最简单的方法是使用 jq 和 CSV 作为中间格式。
编辑:
正如所指出的(感谢 @Leo), the original question did show newline delimited JSON objects, which each on their own conform to rfc4627,但不是所有的格式都在一起。
jq 可以处理 objects 的单个 JSON 数组,尽管通过使用 jq '.[]' <input.json >preprocessed.json
预处理文件,方法与此大致相同。
如果您碰巧正在处理 JSON 文本序列 (rfc7464),幸运的是 jq 也通过 --seq
参数支持了您。
编辑 2:
换行分隔 JSON 和 JSON 文本序列都有一个重要的优点;它们将内存需求降低到 O(1),这意味着您的总内存需求仅取决于您最长的输入行,而将整个输入放在一个数组中需要您的解析器可以处理后期错误(即在第一个 100k 之后元素有语法错误),据我所知通常不是这种情况,或者它必须解析整个文件两次(首先验证语法,然后解析,在丢弃先前元素的过程中,就像 jq --stream
) 这在我看来也很少发生,或者它会尝试一次解析整个输入并一步 return 结果(想想接收一个 Python dict 其中包含整个你说的 50G 输入数据加上开销)通常是内存支持的,因此你的内存占用量增加了你的总数据大小。
编辑 3: 如果遇到任何障碍,请尝试使用 keys_unsorted 而不是 keys。 我自己还没有测试过(我假设我的列已经排序),但是 @Kyle Barron reports that this was needed.
获取 CSV
首先将数据写入文件。 我将在这里假设 data.json。
然后构造 header 使用 jq
:
% head -1 data.json | jq -r 'keys | @csv'
"uri","user_agent"
head -1
是因为我们只想要一行。
jq
的 -r
使输出成为纯字符串而不是 JSON-String 包装 CSV。
然后我们调用内部函数 keys
将输入的键作为数组获取。
我们将其发送到 @csv
格式化程序,后者以引用的 CSV 格式向我们输出一个带有 header 的字符串。
然后我们需要构建数据。
% jq -r '[.[]] | @csv' < data.json
"/","example1"
"/foobar","example1"
"/","example2"
"/foobar","example3"
我们现在获取整个输入并使用 .[]
解构关联数组(映射),然后将其放回简单数组 […]
。
这基本上将我们的字典转换为键数组。
发送到 @csv
格式化程序,我们再次获得一些 CSV。
将所有内容放在一起,我们得到一个 one-liner,其形式为:
% (head -1 data.json | jq -r 'keys | @csv' && jq -r '[.[]] | @csv' < data.json) > data.csv
如果您需要即时转换数据,即没有文件,试试这个:
% cat data.json | (read -r first && jq -r '(keys | @csv),( [.[]] | @csv)' <<<"${first}" && jq -r '[.[]] | @csv')
正在将其加载到 SQLite 中
打开 SQLite 数据库:
sqlite3 somedb.sqlite
现在在交互式 shell 中执行以下操作(假设您将 CSV 写入 data.csv 并希望在 table 中调用my_table
):
.mode csv
.import data.csv my_table
现在关闭 shell 并再次打开它以获得干净的环境。
您现在可以轻松 SELECT
从数据库中进行任何您想做的事情。
综合起来
asciinema 录音:
sqlitebiter 似乎提供了 python 解决方案:
将 CSV/Excel/HTML/JSON/LTSV/Markdown/SQLite/TSV/Google-Sheets 转换为 SQLite 数据库文件的 CLI 工具。 http://sqlitebiter.rtfd.io/
文档: http://sqlitebiter.readthedocs.io/en/latest/
项目: https://github.com/thombashi/sqlitebiter
- 上次更新大约 3 个月前
- 上一期大约 1 个月前关闭,none 打开
- 今天注意到,2018-03-14
无需 CSV 或第 3 方工具 的方法是使用 sqlite3
CLI 工具中提供的 JSON1
extension of SQLite combined with the readfile
extension。
如果输入文件是格式正确的 JSON 文件,例如作为数组给出的示例:
[
{"uri":"/","user_agent":"example1"},
{"uri":"/foobar","user_agent":"example1"},
{"uri":"/","user_agent":"example2"},
{"uri":"/foobar","user_agent":"example3"}
]
那么这个可以读入对应的my_table
table如下。使用 sqlite3 CLI 打开 SQLite 数据库文件 my_db.db
:
sqlite3 my_db.db
然后创建 my_table
使用:
CREATE TABLE my_table(uri TEXT, user_agent TEXT);
最后,my_data.json
中的JSON数据可以用CLI命令插入到table中:
INSERT INTO my_table SELECT
json_extract(value, '$.uri'),
json_extract(value, '$.user_agent')
FROM json_each(readfile('my_data.json'));
除了总体上是一个“更直接”的解决方案外,它还具有处理 JSON NULL 值比 CSV 更一致的优势,否则 CSV 会将它们导入为空字符串。
如果初始 JSON 文件是换行符分隔的 JSON 元素,则可以先使用 jq
转换:
jq -s <my_data_raw.json >my_data.json
可能有一种方法可以使用 JSON1 在 SQLite 中直接执行此操作,但鉴于我已经在使用 jq
进行按摩,我没有继续这样做导入 SQLite 之前的数据。
您可以使用 spyql。 spyql 读取 json 文件(每行 1 个 json 对象)并生成 INSERT 语句,您可以通过管道将其导入 sqlite:
$ spyql -Otable=my_table "SELECT json->uri, json->user_agent FROM json TO sql" < sample3.json | sqlite3 my.db
这假设您已经在 sqlite 数据库 my.db
中创建了一个空的 table。
免责声明:我是spyql的作者。