自制工具将excel文件批量导入到mongodb

时间:2024-03-14 22:52:50

使用方法

  1. 下载此工具(度盘 密码: sbv6),这是一个exe文件,双击可直接运行自制工具将excel文件批量导入到mongodb
  2. 将这个工具放到你要处理的表格所在的目录,比如上图中有一个年级表的示例文件自制工具将excel文件批量导入到mongodb
  3. 确保已启动mongodb服务自制工具将excel文件批量导入到mongodb
  4. 双击脚本工具,启动控制台,会提示你输入要连接/创建的数据库名以及表格所在路径(留空则默认会检查当前目录以及当前目录下的“data”文件夹(如果有的话)),由于我们已经把脚本和表格放在了同一目录下,所以这里直接回车即可自制工具将excel文件批量导入到mongodb
  5. 等待程序执行完毕后,按任意键退出控制台自制工具将excel文件批量导入到mongodb
  6. 在mongo compass中可以查看数据库被更新自制工具将excel文件批量导入到mongodb

注意事项

  1. 工具可能会被杀软误识别为病毒,如果觉得不安全的话,可以自己下载python源码(见本文附录)并自行打包成可执行工具(方法可参考这篇文章
  2. 在启动文件前,请确保MongoDB服务已启动(提示:命令行输入mongod --dbpath $your_db_path$启动)
  3. 默认会把文件名作为表名录入
  4. 暂不支持判断数据库或表是否已存在,为了您的安全,请自行确保该数据库或表没有被覆盖的风险
  5. 该脚本默认会检查当前所在目录是否有名为“data”的文件夹,如果有的话,会将里面的文件作为所有要入库的excel;没有的话会将当前目录中的所有表格类型的文件(“.xlsx”以及“.xls”后缀)作为待入库的表格对象。如有其他需求(例如你的表格文件位于其他盘下的某个目录里),请在脚本启动后根据控制台提示填写你的自定义目录的绝对路径
  6. 暂不支持处理“.csv”后缀的表格文件
  7. 脚本处理完成后,会提示你按任意键退出脚本控制台

附录:python源码

import pymongo
import xlrd
import os
import re


def main(db_name, read_dir='data/'):
    """使用说明

    excel一键转mongo删减版说明(for redevelopment):
		1. 去除了自定义日志模块lk_logger
		2. 开发者请安装pymongo,xlrd模块
    
    功能说明:
        1. 支持批量文件处理
        2. 脚本启动后会弹出控制台,会询问你要导入到哪个数据库(输入数据库名称即可)
        3. 脚本会默认查找目录下的表格文件,或者你也可以自定义某个绝对路径的目录作为参数传入

    注意事项:
        1. 在启动文件前,请确保MongoDB服务已启动(提示:命令行输入"mongod --dbpath $your_db_path$"启动)
        2. 默认会把文件名作为表名录入
        3. 暂不支持判断数据库或表是否已存在,为了您的安全,请自行确保该数据库或表没有被覆盖的风险
        4. 该脚本默认会检查当前所在目录是否有名为"data"的文件夹,如果有的话,会将里面的文件作为所有要入库的excel;没有的话会将当前目录中的所有
        表格类型的文件(xlsx以及xls后缀)作为待入库的表格对象.如有其他需求(例如你的表格文件位于其他盘下的某个目录里),请在脚本启动后根据控制台
        提示填写你的自定义目录的绝对路径
        5. 暂不支持处理".csv"后缀的表格文件
        6. 脚本处理完成后,会提示你按任意键退出脚本控制台

    :param db_name: str. 要连接/创建的数据库名称
    :param read_dir: str. 要读取的文件夹路径,可以传入相对路径或绝对路径,路径名末尾加不加斜杠都可以
    :return:
    """
    
    # 连接/创建数据库
    client = pymongo.MongoClient(host='localhost', port=27017)  # 首先启动客户端
    db     = client[db_name]  # 然后连接/创建数据库
    
    # while True:  # 等待用户输入命令,默认会使用表格的文件名作为待会儿要创建的表的名称
    #     cmd = input('would you want to set filename to be collection name? (y/n)')
    #     if cmd == 'y':
    #         break
    #     elif cmd == 'n':
    #         pass
    #     else:
    #         continue
    
    # 这里脚本默认会查找脚本所在的文件夹有没有名为"data"的文件夹,如果有的话,则将data里面的文件认为是要处理的表格
    # 如果找不到"data"文件夹,则脚本会认为用户把表格放在了与脚本同级的文件夹中,则脚本会在同级搜集所有的文件
    # (后面会自动排除掉类型非表格的文件,所以不要担心脚本把自己当成一个表格)
    if os.path.exists(read_dir):
        if read_dir[-1] != '/':
            read_dir += '/'
            # '../my_custom_data_folder' --> '../my_custom_data_folder/'
            # 这里做一个小处理,如果传入的路径参数末尾不含斜杠,则加上一个斜杠
            # 之所以这样做,是为了在后面打开workbook路径的时候不会出错
    else:
        read_dir = os.path._getfullpathname(os.path.abspath(__file__))
        # --> r'E:\workspace\smart_tools\excel_2_mongodb_tool\main_app.py'
        read_dir = read_dir.replace('\\', '/')
        # --> 'E:/workspace/smart_tools/excel_2_mongodb_tool/main_app.py'
        read_dir = re.sub(r'(/)(?!.*\1).+$', '', read_dir) + '/'
        # --> 'E:/workspace/smart_tools/excel_2_mongodb_tool/'
        print('current directory = {}'.format(read_dir))
        """注意事项:
        
        获取当前脚本所在的目录:
            # 不要用:
            read_dir = os.path.dirname(__file__)
            # 该语句在python中可以实现,但在打包成exe后,使用该语句会返回空值错误
            
            # 要用:
            read_dir = os.path._getfullpathname(os.path.abspath(__file__))
            read_dir = re.sub(r'(/)(?!.*\1).+$', '', read_dir)
            # 先获取文件的绝对路径(含脚本文件名),再把脚本名用正则去掉
            
        另外需要注意的是正则的使用:
            # e.g. read_dir = 'E:/workspace/smart_tools/excel_2_mongodb_tool/main_app.py'
            
            # 不要用:
            read_dir = re.sub(r'/.+$', '', read_dir)
            # 正则默认会贪婪匹配,该语句会匹配到第一个斜杠,结果会返回"E:"
            
            # 要用:
            read_dir = re.sub(r'(/)(?!.*\1).+$', '', read_dir)
            # 该语句会匹配斜杠最后一次出现的位置,从而正确地去除脚本名,结果会返回"E:/workspace/smart_tools/excel_2_mongodb_tool"
        
        当然如果觉得正则麻烦的话,也可以用:
            # e.g. read_dir = 'E:/workspace/smart_tools/excel_2_mongodb_tool/main_app.py'
            read_dir = '/'.join(read_dir.split('/')[:-1]) + '/'
            # --> 'E:/workspace/smart_tools/excel_2_mongodb_tool/'
        """
    
    files = os.listdir(read_dir)  # --> ['a.xlsx', 'b.xls', 'c.xlsx', ...]
    if not files:
    	pring('[W] no excel found in your directory!')
        raise AttributeError
    
    for file in files:
        if '.' in file and 'xls' in file[-4:]:  # 目前仅支持xlsx和xls类型的文件的识别
        	print('------------------------------------------------ file = {}'.format(file))  # 打印一条分割线
            
            table_name    = file.split('.')[0]  # 'a.xlsx' --> ['a', 'xlsx'] --> 'a'
            current_table = db[table_name]      # 以文件名为表名,创建一张表
            
            workbook      = xlrd.open_workbook(read_dir + file)  # --> open_workbook('data/a.xlsx')
            sheet         = workbook.sheet_by_index(0)           # 获得sheet1的数据
            
            rows_tag      = sheet.row_values(0)  # 获得第一行的表格数据,一般来说这就是标题头,可以作为字典的键名使用
            print('rows_tag = {}'.format(rows_tag))
            
            for j in range(1, sheet.nrows):  # 开始遍历表格的每一行,将每一行的数据作为一个对象录入到这张表中
                row_data = dict(zip(rows_tag, sheet.row_values(j)))
                """example
                
                举个例子说明一下zip(list, list)的作用:
                    a = zip(['iii', 'jjj', 'kkk'], ['uuu', 'vvv', 'www', 'xxx', 'yyy', 'zzz'])
                    print(a)        # --> <zip object at 0x0000019F876A8C48>
                    print(dict(a))  # --> {'iii': 'uuu', 'jjj': 'vvv', 'kkk': 'www'}
                    print(list(a))  # --> [('iii', 'uuu'), ('jjj', 'vvv'), ('kkk', 'www')]
                
                所以经过此步骤我们得到的row_data为一个字典对象:
                    {
                        'name'  : 'Mark',
                        'gender': 'male',
                        'age'   : '23',
                        ...
                    }
    
                pymongo可以接受dict类型的数据,所以接下来直接将row_data插入到表中即可
                """
                current_table.insert_one(row_data)
    
    input('script executed over, press anykey to leave... ')


if __name__ == '__main__':
    my_db        = input('please input the db name which would be created or connected to: ')
    my_data_path = input("please input the data path (press enter to use default path: 'data/'): ")
    if my_data_path:
        main(my_db, my_data_path)
    else:
        main(my_db)