二维码

使用Python将数据从MongoDB导入MySQL

1821 人阅读 | 时间:2018年12月03日 17:14

MySQL Shell 8.0.13(GA)引入了一项新功能,允许您轻松地将JSON文档导入MySQL。这篇新功能的基础知识在之前的博客文章中有所描述在本博客中,我们将提供有关此功能的更多详细信息,重点关注许多人感兴趣的实际用例:如何将MongoDB中的JSON数据导入MySQL。可以应用相同的“配方”将数据从其他文档存储数据库导入MySQL,只要它们能够生成或导出数据到JSON即可。

无论出于何种原因,迁移到不同数据库产品的任务不应掉以轻心,并且在某些情况下可能非常复杂。在其他方面,它取决于数据库服务器的数量及其在系统中的组织(单一服务器Vs复杂复制拓扑),数据大小,执行此任务的要求和可用资源。应定义全面详细的计划以确保成功,包括执行所有必需步骤和相应的操作/工具。

注意:在开始迁移生产数据库系统之前,强烈建议您首先迁移数据样本并测试最终结果,以确保它符合您的期望和要求。这也可以让您测试迁移计划。

每个迁移计划都是不同的,并且特定于每个用例,但都可能包括常见步骤,例如更新应用程序以使用新数据库,以及导出/导入数据库数据。MySQL Shell中用于导入JSON数据的新功能有助于我们以更简单的方式执行此步骤。让我们看看在实践中如何使用Python将数据从MongoDB导入MySQL。

将数据从MongoDB导出到JSON

MongoDB允许您将所有数据导出到JSON,但它生成MongoDB Extended JSON的严格模式表示幸运的是,MySQL Shell JSON导入功能允许您使用选项' convertBsonOid ' 轻松转换BSON ObjectId类型

注意:如果您的数据包含除ObjectId之外的其他BSON类型,它们以严格模式表示(例如,BinData,Date,Timestamp,NumberLong,NumberDecimal等),那么您可能需要手动将这些类型的转换处理为基础您的要求(例如,在导入/导出过程中使用您自己的自定义转换脚本,或在应用程序级别转换它们)。有关BJSON类型及其在严格模式下的表示的更多信息,请参阅:BSON数据类型和关联表示

您需要做的第一件事是将所有MongoDB数据导出到JSON文档。例如,假设您在“ 测试”数据库中有两个集合,名称为:restaurants和neighboors。您可以使用以下说明将MongoDB数据导出到JSON文档(每个集合一个文件):

1
2
3
4
5
6
7
$ mongoexport --db test --collection restaurants --out restaurants_mongo.json
2018-10-08T18:38:19.104+0100 connected to: localhost
2018-10-08T18:38:19.633+0100 exported 25359 records
$ mongoexport --db test --collection neighborhoods --out neighborhoods_mongo.json
2018-10-08T18:38:45.923+0100 connected to: localhost
2018-10-08T18:38:46.382+0100 exported 195 records

因此,您将获得两个带有数据的JSON文件“restaurants_mongo.json”和“neighborhoods_mongo.json”。

使用Python将JSON数据导入MySQL

接下来,您只需使用新的MySQL Shell功能将生成的JSON文件导入MySQL数据库。为此,我们在下一个示例中使用Python函数“ util.import_json ”。但是,使用命令行可以实现相同的效果,如我们之前的博文中所示

使用Python将数据从MongoDB导入MySQL

命令:
\py 
util.import_json("/path_to_file/neighborhoods_mongo.json", {"schema": "test", "collection": "neighborhoods", "convertBsonOid": True}) 
>util.import_json("/path_to_file/restaurants_mongo.json", {"schema": "test", "table": "restaurants", "convertBsonOid": True})

正如您所看到的,选项' convertBsonOid '与true值一起使用,以导入将MongoDB Object Id(OID)转换为正确值的两个文件。特别是,在将JSON数据导入集合的情况下,这是必需的,因为OID被转换为MySQL用于标识每个存储文档的集合Id(更具体地,' _ id '列和' _id '字段用于集合中的每个文档),否则在尝试将包含OID的字段导入集合中的MySQL文档Id(' _ id ')时将发出错误

使用Python函数util.import_json()将第一个文件“neighborhoods_mongo.json”导入集合' neighborhoods ' 使用相同的功能将第二个文件“restaurants_mongo.json”导入到表' restaurants '中。在这两种情况下,目标集合和表都不存在,因此它是由JSON导入函数自动创建的。

有关JSON导入实用程序的更多详细信息,请参见此处您也可以直接使用MySQL Shell中的帮助来获取有关该函数的快速信息,只需输入:“ \ h import_json ”。

将JSON导入集合和表之间的区别

使用不同的目标对象(集合或表)在导入结果上有一些细微的差别。让我们看一下结果数据的结构,以突出这些差异。

使用Python将数据从MongoDB导入MySQL

命令:
\use test
db.get_collections() 
session.sql('SHOW TABLES') 
session.sql('SHOW CREATE TABLE test.neighborhoods') 
>session.sql('SHOW CREATE TABLE test.restaurants')

首先,正如预期的那样,我们可以观察到' 餐馆 '数据未被列为集合,因为它是专门导入到表中的。但是,所有导入的文件都列为表,甚至是导入到集合的JSON文档。这是因为集合也在内部存储为MySQL中的表,但具有非常特定的结构。

查看“邻域”和“餐馆”表的“SHOW CREATE TABLE”语句的结果,可以看出它们之间的差异。在这两种情况下,JSON文档实际上都存储在JSON类型的“ doc ”列中区别在于识别栏。对于集合“ 邻域 ”,标识由“ _id ”列保存,该列与JSON文档中的“ _id ”字段匹配,该字段包含导入期间转换的OID的值。因此,OID实际上将匹配MySQL中每个导入的JSON文档的Id,用作主键。在表' 餐馆 ' 的情况下,标识由''持有'id '列是一个自动增量整数,表示为每个JSON文档(行)生成一个新标识。因此,原始OID将以某种方式被忽略,即不用作主键,尽管每个JSON文档中_id字段将包含从导入转换的OID值。

实际上,这种差异会影响您使用导入数据的方式。如果您选择一个集合作为导入的目标,您将能够利用所有MySQL文档存储功能(NoSQL + SQL)。另一方面,如果您选择一个表作为导入的目标,您将“限制”为可用的JSON类型功能和MySQL本机提供的JSON函数来操作您的JSON数据(仅限SQL)。

注意: MongoDB与MySQL文档存储的命令之间存在一些相关的语法差异,这可能有助于了解何时更新应用程序以使用MySQL。您可以在以下博文中找到有关它的更多信息:第一部分第二部分第三部分

如何为某些导入的数据创建新列

从前面的示例中,我们可以观察到所有导入的数据都存储在JSON类型的单个列中但是,在某些情况下,可能需要将此数据的一部分放在另一列中,例如,在其上创建索引以改善某些查询的执行时间。让我们看一个简单快捷的例子。假设我们将一些额外的JSON数据从“primer-dataset.json”导入到新的'my_restaurants'表中,并且我们的应用程序需要查询所有餐馆的名称以获取特定类型的菜肴。

使用Python将数据从MongoDB导入MySQL

命令:
util.import_json("/path_to_file/primer-dataset.json", {"schema": "test", "table": "my_restaurants"}) 
shell.options.outputFormat = "vertical" 
>session.sql('EXPLAIN SELECT doc->>"$.name" AS name FROM test.my_restaurants WHERE doc->>"$.cuisine" = "Italian"')

正如您所看到的,使用EXPLAIN语句显示有关查询执行计划的信息,我们可以验证查询是否将执行全表扫描以检索所需信息,这是不推荐的(特别是对于包含大量数据的表) 。幸运的是,通过为我们要用于过滤结果的属性添加新列和索引,可以使用ALTER TABLE语句在生成的列上创建二级索引,从而轻松解决此问题

使用Python将数据从MongoDB导入MySQL

命令:
session.sql('ALTER TABLE test.my_restaurants ADD COLUMN cuisine VARCHAR(80) GENERATED ALWAYS AS (doc->>"$.cuisine") VIRTUAL, WITH VALIDATION') 
session.sql('ALTER TABLE test.my_restaurants ADD INDEX cuisine_idx (cuisine)') 
>session.sql('EXPLAIN SELECT doc->>"$.name" AS name FROM test.my_restaurants WHERE cuisine = "Italian"')

第一个ALTER TABLE语句将新列'cuisine'添加到'my_restaurants'表中,从每行的JSON数据的'cuisine'属性(在'doc'列中)中提取该列的值。在此特定情况下,创建了一个虚拟列并执行了验证以确保生成的值不在范围之外,但是其他选项可用于创建新列,有关详细信息,请参阅:ALTER TABLE和Generated Columns然后,执行第二个ALTER TABLE以在新的“cuisine”列上添加索引。

现在,分析EXPLAIN的结果,我们可以验证查询执行成本是否低得多,因为使用了索引(没有全表扫描)。

注意: 在上图中,我们显示了从MySQL Workbench获得的查询执行计划图,以便更好地直观地说明每种情况的成本。

立即尝试并将您的反馈发送给我们

MySQL Shell可从以下链接下载。

可以在此处找到MySQL Shell的文档:https//dev.mysql.com/doc/mysql-shell/8.0/en/

以上示例中使用的示例JSON数据可通过以下链接公开获取。您可以下载并亲自试用。


取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

©著作权归作者所有:来自ZhiKuGroup博客作者没文化的原创作品,如需转载,请注明出处,否则将追究法律责任 来源:ZhiKuGroup博客,欢迎分享。

评论专区
  • 昵 称必填
  • 邮 箱选填
  • 网 址选填
◎已有 0 人评论
搜索
作者介绍
30天热门
×
×
关闭广告
关闭广告
本站会员尊享VIP特权,现在就加入我们吧!登录注册×
»
会员登录
新用户注册
×
会员注册
已有账号登录
×