简体   繁体   English

通过 CSV 导出/导入 mysql json object

[英]Export/import mysql json object via CSV

I'm working with a pair of PHP scripts.我正在使用一对 PHP 脚本。 One script reads data from a MYSQL database and exports it to a csv file then a second script uploads the exported csv file to another MySQL database instance using csv. One script reads data from a MYSQL database and exports it to a csv file then a second script uploads the exported csv file to another MySQL database instance using csv. The structure of the database tables A (export) and B (import) are identical.数据库表 A(导出)和 B(导入)的结构相同。

These scripts work fine for "normal" MySQL tables and column types.这些脚本适用于“正常”MySQL 表和列类型。 However, the import fails when we apply them to a MySQL table that stores a JSON object in one of the columns (MySQL column type is "json").但是,当我们将它们应用于 MySQL 表时,导入失败,该表在其中一列中存储了 JSON object(MySQL 列类型为“json”)。

The script that exports the data works as expected, producing a CSV file with the JSON object surrounded by double quotes...just like the other values in the row.导出数据的脚本按预期工作,生成 CSV 文件,其中 JSON object 被双引号括起来......就像行中的其他值一样。
The row in the exported CSV file looks like this (the last item is a complex json object, abbreviated for simplicity):导出的 CSV 文件中的行如下所示(最后一项是复杂的 json object,为简单起见缩写):

"894","Somebody","Related","2020-02-20","{"name1":"value1","name2":"value2","name3":"value3"}","expired"

In the PHP script to export the data it's essentially this:在 PHP 脚本中导出数据基本上是这样的:

$rowStr =   "894","Somebody","Related","2020-02-20","{"name1":"value1","name2":"value2","name3":"value3"}","expired";
file_put_contents($filepath, trim($rowStr), FILE_APPEND);

No issues with the export.出口没有问题。 Row appears in the CSV file as expected (same format as above).行按预期出现在 CSV 文件中(格式与上述相同)。

My code to read the csv into the other database looks like this:我将 csv 读入其他数据库的代码如下所示:

    $allRows = array_map('str_getcsv',file($fp)); // read the exported csv file where $fp is the path to the file

    foreach($allRows as $i => $row) {
        //get the col_names from the 2nd database table (identical to the first) where $ac-> is the class that handles data queries
        $col_names = $ac->get_table_column_names('databasename',$tablename);

        $update_arr = array();
        foreach($col_names as $i => $cname) {

            $update_arr[$cname['COLUMN_NAME']] = $val;              
        }

        //and write the row to the 2nd db's table
        $ac->create_update_table($update_arr,$tablename,FALSE);
   }

And, if it matters, here are the Queries used in the "get_table_column_names" and "create_update_table" functions:而且,如果重要的话,这里是“get_table_column_names”和“create_update_table”函数中使用的查询:

get_table_column_names //Using PDO get_table_column_names //使用PDO

SELECT COLUMN_NAME,COLUMN_DEFAULT,DATA_TYPE FROM information_schema.columns WHERE table_schema = :db AND table_name = :table

create_update_table创建更新表

INSERT INTO 'tablename' (field1, field2, field3, field4,json_object_column) VALUES ("894","Somebody","Related","2020-02-20","{"name1":"value1","name2":"value2","name3":"value3"}")

The problem is that, when importing, the row is converted to an array like this:问题是,在导入时,该行被转换为这样的数组:

array (
[0] = "894",
[1] = "Somebody",
[2] = "Related",
[3] = "2020-02-20",
[4] = "{name1":"value1",
[5] = "name2:"value2",  //should be part of node 4
[6] = "name3:"value3"}", //should be part of node 4
[7] = "expired"
);

What's happening is that the "," inside the JSON object is being treated as a field separator and the JSON is broken up into array nodes.发生的事情是 JSON object 中的“,”被视为字段分隔符,并且 JSON 被分解为数组节点。 Other than writing a script to detect fields that start with "{ and end with }", how can I read the entire json string as one field (as it is in the database)?除了编写脚本来检测以“{ 并以 }”结尾的字段之外,我如何将整个 json 字符串作为一个字段读取(因为它在数据库中)? or, perhaps, is there a better way to output the string so that it can be read as one item?或者,也许有更好的方法来 output 字符串,以便可以将其作为一项读取?

If instead of just writing out the data using something like file_put_contents() you use some of the methods designed for CSV files, this will do most of the work for you...如果不只是使用file_put_contents()之类的东西写出数据,而是使用为 CSV 文件设计的一些方法,这将为您完成大部分工作......

To write the data use fputcsv() and this escapes the delimiter (in this case the " becomes "")...要写入数据,请使用fputcsv()并转义分隔符(在这种情况下,“变成”)......

$row = ["894","Somebody","Related","2020-02-20",'{"name1":"value1","name2":"value2","name3":"value3"}',"expired"];

$fh = fopen($filepath, "a");
fputcsv($fh, $row);
fclose($fh);

which will write to the file这将写入文件

894,Somebody,Related,2020-02-20,"{""name1"":""value1"",""name2"":""value2"",""name3"":""value3""}",expired

and then to read from the file, just read a line at a time and use fgetcsv() ...然后从文件中读取,只需一次读取一行并使用fgetcsv() ...

$fh = fopen($filepath, "r");
print_r(fgetcsv($fh));   // This in a loop to read all lines
fclose($fh);

which shows这表明

Array
(
    [0] => 894
    [1] => Somebody
    [2] => Related
    [3] => 2020-02-20
    [4] => {"name1":"value1","name2":"value2","name3":"value3"}
    [5] => expired
)

One way of solving this is to create a new copy of the array and manipulate the new array and add json as a sliced part of the original array.解决此问题的一种方法是创建数组的新副本并操作新数组并添加 json 作为原始数组的切片部分。

$allRows = array_map('str_getcsv',file($fp)); 

$new_arr = [];
foreach($allRows[0] as $key=>$item) {

    $json = false;

    if (substr($item,0,1) == '{') {
        $json_start = $key;
        $json = true;
    }

    if (substr($item,-2,2) == '}"') {
        $json_stop = $key;
        $json = true;

        //Slice json-part from original array (in your case 4,5,6)
        $sl = array_slice($allRows[0], $json_start, ($json_stop-$json_start)+1);

        //Add the sliced part into key where json started
        $new_arr[$json_start] = implode('',$sl);         
    }

    if ($json === false) $new_arr[] = $item;
}

And then you have your expected array in $new_arr .然后你在$new_arr中有你期望的数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM