美文网首页高性能MySQL
Mongodb嵌套数组转MySQL

Mongodb嵌套数组转MySQL

作者: mrwoody | 来源:发表于2019-04-29 15:44 被阅读1次

    因为目标站点返回的数据是json格式,一方面为了学习新知识,另一方面是想偷个懒,所以直接使用Mongdb保存爬虫结果。
    最近有个新需求:使用Data-V对这些存量数据制作数据大屏,但目前Data-V支持的数据库只有关系型数据库(当然也可以写API来给Data-V投喂数据,但是如此好像更麻烦些),因此需要将数据从Mongodb 迁移到 MySQL。
    最朴素的想法,当然是用Python写一段脚本,从Mongodb读取需求的字段,然后再逐条插入MySQL中。这个方法肯定可以获得预期的效果,预计100行以内的代码都能完成。但是,MongoDB和MySQL既然已经是很成熟的产品了,对数据迁移应该有更好的解决方案,自己再造一遍轮子实在不是个好主意。

    寻找新方法

    之前查看MongoDB的根目录mongodb安装路径\bin发现有一个叫做mongoexport.exe的文件,第一眼就觉得是想要找的功能。

    > mongoexport.exe --help
    > Usage:
      mongoexport <options>
    
    Export data from MongoDB in CSV or JSON format.
    
    See http://docs.mongodb.org/manual/reference/program/mongoexport/ for more information.
    

    利用这个工具可以将查询结果导出为CSV或者JSON格式,MySQL的数据导入工具刚好可以直接导入以上两种格式的数据。看来这应该就是我们需要的路径了。
    mongoexport.exe的参数挺多,按照上一段代码的方法可以仔细查看,我使用的几个参数如下:

    > mongoexport.exe /uri:mongodb://username:password@host:port/database /c collection /f field /o resultPATH /jsonArray
    /uri 导出数据的mongodb的uri,username填用户名,password密码,host IP, port 端口,database 验证用户名、密码的数据库。
    /c 想要导出的Collections
    /f 需要导出的字段
    /o 导出文件的路径及文件名
    /jsonArray 导出json数组而非jsonline
    

    如果需要查询,可以使用 \q参数输入查询语句。接下来,使用MySQL的文件导入工具即可将数据导入到MySQL中,速度还是挺有保障的。
    这种方法针对形如{ "_id" : 0, "nref_date" : "20190318-20190416", "nname" : "未知", "nvalue" : 1 }的数据是比较有效的,但涉及到拥有嵌套数组的数据就显得有些难以处理了。
    例如:

    image.png
    如何将上图中list[0]的item_list中的5对(key, value)添加ref_date存储成MySQL中的5条记录?

    新的挑战

    之前看文档的时候了解到,MongoDB有聚合操作(aggregate),也支持管道(pipeline)操作。将数组解包使用的是"$unwind"操作,嵌套的数组用点号分隔即可,还是先回顾下常用的一些聚合操作吧:

    $project:修改输入文档结构,可用来新增、删除域,或者构建新结果。
    $match:输出符合条件的文档,可以用来过滤树。
    $limit:用来限制管道返回的文档数。
    $skip:在聚合管道中跳过指定数量的文档。
    $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
    $group:将集合中的文档分组。
    $sort:排序。
    $out:将管道聚合操作返回的结果另存成一个collections,必须位于管道的最后一个操作。
    

    本例中可以使用将list.item_list解包,注意因为list也是数组,所以使用了两次$unwind:

    db.collections.aggregate([{"$unwind": "$list"}, {"$unwind": "$list.item_list"})
    

    执行过后,得到如下形状的5个文档:

    {
        "_id" : ObjectId("5cb595a2923d072acc8bdf8b"),
        "ref_date" : "20181129",
        "list" : {
            "index" : "access_source_session_cnt",
            "item_list" : {
                "key" : 36,
                "value" : 19
            }
        }
    }
    

    但输出的形式,和我们想要的结果还不太一样,如果直接使用MySQL的导入工具还是无法找到对应字段的映射关系。
    接下来使用$project修改返回文档的结构,直接在上面的管道中新增

    db.collections.aggregate([{"$unwind": "$list"}, {"$unwind": "$list.item_list"}, {"$project": {"newkey": "$list.item_list.key", "newvalue": "$list.item_list.value", "new_ref_date": "$ref_date"}}])
    

    输出的第一个元素变成以下结构:

    {
        "_id" : ObjectId("5cb595a2923d072acc8bdf8b"),
        "newkey" : 29,
        "newvalue" : 17,
        "new_ref_date" : "20181129"
    }
    

    如果使用的MongoDB支持将查询结果导出成JSON,那到这里已经可以完成任务了!遗憾的是我用的Robot 3T貌似并不支持,不过也没有关系,我们使用$out操作符将管道的聚合结果另存成一个Collections即可。
    最终的管道聚合操作有四步操作:

    db.collections.aggregate([
    {"$unwind": "$list"}, 
    {"$unwind": "$list.item_list"}, 
    {"$project": {"newkey": "$list.item_list.key", "newvalue": "$list.item_list.value", "new_ref_date": "$ref_date"}},
    {"$out": "outputjson"}
    ])
    

    接下来使用mongoexport.exe工具将outputjson导出成JSON格式即可导入MySQL了!

    MongoDB多层嵌套脑壳疼、查个文档又尽是英文、阿里云Data-v居然都不支持,以后不会再用了!!!
    卧槽原来可以这样!
    真香!

    相关文章

      网友评论

        本文标题:Mongodb嵌套数组转MySQL

        本文链接:https://www.haomeiwen.com/subject/tieynqtx.html