具有额外值的Python MySQL连接器ExecuteMy

具有额外值的Python MySQL连接器ExecuteMy,python,mysql,dictionary,Python,Mysql,Dictionary,当使用MySQL的executemany()插入数据时,是否有一种内置方法可以忽略字典中的字段 我需要从JSON文件中提供给我的相对较大的数据集中插入数据。因此,JSON数据的基本布局如下: { "data" : [ { "f1" : 42, "f2" : "abc", "f99" : "useless stuff" }, { "f1" : 43, "f2" : "def", "f99" : [ "junk", "here" ] }, {

当使用MySQL的
executemany()
插入数据时,是否有一种内置方法可以忽略字典中的字段

我需要从JSON文件中提供给我的相对较大的数据集中插入数据。因此,JSON数据的基本布局如下:

{
    "data" : [
        { "f1" : 42, "f2" : "abc", "f99" : "useless stuff" },
        { "f1" : 43, "f2" : "def", "f99" : [ "junk", "here" ] },
        { "f1" : 44, "f2" : "ghi", "f99" : { "thing" : 99 } }
    ]
}
我的插入设置如下所示:

import json
import mysql.connector
with open( 'huge_data_dump.json', 'rb' ) as fh:
    data = json.load( fh )
connection = mysql.connector.connect( **mysql_config )
cursor = connection.cursor()
query = 'INSERT INTO `example` ( `f1`, `f2` ) VALUES ( %(f1)s, %(f2)s )'
cursor.executemany( query, data[ 'data' ] )
cursor.close()
connection.close()
目标表如下所示:

CREATE TABLE `example` ( `f1` INT, `f2` VARCHAR( 10 ) )
但是,当我运行此命令时,会出现一个错误:

Failed processing pyformat-parameters; Python 'list' cannot be converted to a MySQL type
如果我将导入限制为仅限于示例数据集中的第一行,则插入操作将非常有效:

cursor.executemany( query, data[ 'data' ][ : 1 ] )
问题来自
f99
字段中的无关数据,该字段包含谁知道的内容。这对我来说很好:我不想从
f99
获得任何信息。但是,MySQL连接器似乎希望在检查查询之前将整个记录的字典转换为安全字符串,以查看是否需要该值

我尝试使用生成器函数将数据集过滤到对
executemany()
的调用中,但连接器抱怨只能接受元组和列表(我觉得这是一个相当不符合Pythonic的接口)

我最后的办法是将数据复制到新的字典中,并在将数据传递到
executemany()
之前过滤掉不需要的字段。然而,这些数据集已经足够大了,我正在考虑将它们从JSON源文件中以每次几百次插入的方式进行流式传输。试图消除所有不需要的数据的附加循环将是一种浪费,需要维护更多的代码。我真诚地希望我忽略了文档中没有涵盖或掩盖的内容


我想我可以开始研究输入上的一些自定义JSON过滤,但我还是希望有一种简单的内置方法来解决(似乎是)一个相对常见的用例。

您可以使用一个生成器,为数据列表中的每个记录创建所需列的元组:

(d["f1"], d["f2"] for d in data['data'])
将此生成器传递给executemany函数应能正常工作

编辑:您可能需要将查询更改为

query = 'INSERT INTO `example` ( `f1`, `f2` ) VALUES ( %s, %s )'

但我对此并不确定。

亲爱的未来的人们:

经过一段时间的斗争,我决定从输入端解决这个问题

内置的JSON实现并不完全支持流式传输,但您可以在JSON数据加载到解释器内存中时指定JSON数据各个部分的自定义解码。我滥用截获所有object to dictionary解码的能力,决定继续操作那里传入的数据

还需要注意的是:MySQL连接器对一个事务中传递的数据量有一些限制,因此我继续在解码器中缓存了数百个这些“转换”字典,并在JSON
load()
函数读取文件时将它们插入数据库

简言之: 注意事项:
  • 解析器加载完数据后,仍然需要插入缓存中的任何剩余内容。我最终在CustomDecoder实例外部维护了缓存,以便在内部创建的CustomDecoder消失后可以刷新缓存
  • 管理查询和游标对象需要更多的代码来保持界面相对干净。我决定创建一个分配给类属性的回调处理程序。回调处理程序恰好知道如何查找当前游标和查询

  • 好主意,但是内联生成器的失败方式与函数生成器的失败方式相同。连接器进行了太多类型检查,无法正常工作。我可以使用列表理解,但它似乎是在传递给
    executemany()
    函数之前对整个列表进行了迭代。
    import json
    
    class CustomDecoder( json.JSONDecoder ):
    
        allowed = [ 'f1', 'f1' ]
    
        def __init__( self, **kwargs ):
            kwargs[ 'object_hook' ] = self.object_to_dict
            super( CustomDecoder, self ).__init__( **kwargs )
            self.cache = []
    
        def object_to_dict( self, data ):
    
            # this check just identifies the object we need to insert
            if 'f1' in data:
    
                # permit allowed fields from the incoming dictionary
                data = dict(
                    ( k, v )
                    for k, v in data.iteritems()
                    if k in self.allowed
                )
    
                # add data to batch cache
                self.cache.append( data )
    
                # check cache status
                if len( self.cache ) >= 200:
    
                    # insert the cached records as a group for performance
                    ### cursor.executemany( query, self.cache )
    
                    # dump the cache
                    self.cache = []
    
            # return modified data or pass through un-modified data
            return data
    
    # connect to database, grab a cursor to it, set up the query
    
    with open( 'import_file.json', 'rb' ) as fh:
        data = json.load( fh, cls = CustomDecoder )
    
    # at this point, everything but left-overs in the cache should be inserted