// just for convenience (pathExists)
import {} from "https://deno.land/x/simple_shell@0.9.0/src/stringUtils.ts";
/**
* @description
* convert a json db to csv and then to sqlite
*
* @note
* `sqliteTableConstructor` is a string that is used to create the table, if it is specified the csv file *should not* contain a header row.
* if it's not specified then the csv file *must* contain a header row so it can be used to infer the column names.
*/
const jsonToSqlite = async (
{
jsonDbPath,
jsonToCsvFn,
sqliteDbPath,
sqliteTableConstructor,
tableName,
}: {
jsonDbPath: string;
sqliteDbPath: string;
tableName: string;
sqliteTableConstructor?: string;
// deno-lint-ignore no-explicit-any
jsonToCsvFn: (jsonDb: any) => string;
},
) => {
// convert it into csv
const csvDbPath = `${jsonDbPath.replace(".json", "")}.csv`;
if (csvDbPath.pathExists()) {
console.log(`${csvDbPath} already exists`);
} else {
const db = JSON.parse(await Deno.readTextFile(jsonDbPath));
const csv = jsonToCsvFn(db);
await Deno.writeTextFile(csvDbPath, csv);
}
// convert it to sqlite
if (sqliteDbPath.pathExists()) {
console.log(`${sqliteDbPath} already exists`);
} else {
const sqlite3 = Deno.spawnChild("sqlite3", {
args: [sqliteDbPath],
stdin: "piped",
stderr: "null", // required to make sqlite3 work
});
await sqlite3.stdin.getWriter().write(
new TextEncoder().encode(
".mode csv\n" +
(sqliteTableConstructor ? `${sqliteTableConstructor};\n` : "") +
`.import ${csvDbPath} ${tableName}\n` +
".exit\n",
),
);
await sqlite3.status;
}
};
6条答案
按热度按时间yiytaume1#
我发现最简单的方法是使用jq和CSV作为中间格式。
获取CSV
首先将您的数据写入文件。我将在这里假定data.json。
然后使用
jq
构造头部:head -1
是因为我们只需要一行。jq
的-r
使输出成为普通字符串,而不是 Package CSV的JSON字符串。然后,我们调用内部函数keys
以数组形式获取输入的键。我们将其发送到@csv
化程序,该格式化程序以引用的CSV格式输出带有标题的单个字符串。然后,我们需要构建数据。
现在我们获取全部输入,并使用
.[]
解构关联数组(Map),然后将其放回一个简单的数组[…]
中。这基本上将我们的词典转换为键的数组。发送到@csv
化程序,我们再次获得一些CSV。把所有这些放在一起,我们得到一个简单的一行,形式是:
如果您需要在没有文件的情况下动态转换数据,请尝试以下操作:
加载到SQLite中
打开SQLite数据库:
现在,在交互式外壳中执行以下操作(假设您将CSV写入data.csv并希望它位于名为
my_table
的表中):现在关闭外壳,然后再次打开,以获得干净的环境。现在,您可以轻松地从数据库中使用
SELECT
并做任何您想做的事情。把这一切放在一起
就在那里进行asciinema录制:
编辑
jq '.[]' <input.json >preprocessed.json
对文件进行预处理,以大致相同的方式处理单个JSON对象数组。如果您碰巧正在处理JSON文本序列(rfc7464),那么幸运的是,jq也通过--seq
参数为您提供了支持。jq --stream
的情况一样),这也很少发生,或者,它会尝试一次解析整个输入并在一个步骤中返回结果(想象一下,接收到一个包含整个50G输入数据加上开销的Python字典),这通常是由内存支持的,因此您的内存使用量增加了大约您的总数据大小。map_values()
不同,map()
根据注解稍作修改,将对象转换为与[.[]]
相同的键,从而使Map更具可读性)。键不受影响,如果您“真的”使用复杂类型作为键(这可能甚至不符合JSON,但我现在懒得去查找它),您可以对与键相关的Map执行相同的操作。pbpqsu0x2#
无需CSV或第三方工具的一种方法是结合使用SQLite的
JSON1
extension和sqlite3
CLI工具中提供的readfile
扩展。总的来说,这是一种“更直接”的解决方案,其优点是比CSV更一致地处理JSON null值,否则CSV会将它们作为空字符串导入。如果输入文件是格式良好的JSON文件,例如以数组形式给出的示例:
则可以将其读入相应的
my_table
表中,如下所示。使用sqlite3 CLI打开SQLite数据库文件my_db.db
:然后使用以下命令创建
my_table
:最后,可以使用CLI命令将
my_data.json
中的JSON数据插入到表中:如果初始JSON文件是换行符分隔的JSON元素,则可以首先使用
jq
进行转换,方法是:jq
来处理数据。*a5g8bdjr3#
Sqlitebiter似乎提供了一种Python解决方案:
一个CLI工具,用于将CSV/Excel/HTML/JSON/LTSV/Markdown/SQLite/TSV/Google-Sheets转换为SQLite数据库文件。http://sqlitebiter.rtfd.io/
文档:http://sqlitebiter.readthedocs.io/en/latest/
项目:https://github.com/thombashi/sqlitebiter
yr9zkbsy4#
您可以使用spyql。Spyql读取json文件(每行1个json对象)并生成INSERT语句,您可以将这些语句通过管道传输到SQLite:
这里假设您已经在SQLite数据库
my.db
中创建了一个空表。免责声明:我是间谍网站的作者。
ojsjcaue5#
以下是编译成Deno脚本的第一个答案:
用法示例:
Edit1:
编辑2:
下面的代码将从json数据库创建一个新的SQL数据库。
2admgd596#
使用换行符分隔的JSON对象文件,包括数据中的
\n
。添加标题列名并确保JSON是紧凑的(每条记录一行)。
使用列分隔符
\t
将JSON和标头作为“CSV”导入到临时表中,这在JSON中不会出现。然后通过SQLites JSON functions创建真实的表。