Php 如何将包含100000条记录的90MB JSON文件解析、排序和打印为CSV? 背景

Php 如何将包含100000条记录的90MB JSON文件解析、排序和打印为CSV? 背景,php,json,performance,sorting,memory,Php,Json,Performance,Sorting,Memory,我正在尝试完成一个代码挑战,我需要重构一个简单的PHP应用程序,该应用程序接受一个JSON文件,按注册日期对其进行排序,并将其输出到CSV文件。提供的程序已经运行,在小输入下运行良好,但在大输入下故意失败。为了完成挑战,应该修改程序,使其能够像现在一样,在不耗尽内存的情况下解析和排序100000条记录,90MB的文件 在当前状态下,程序使用file\u get\u contents(),然后使用json\u decode(),然后使用usort()对项目进行排序。这在小样本数据文件中工作良好,但

我正在尝试完成一个代码挑战,我需要重构一个简单的PHP应用程序,该应用程序接受一个JSON文件,按注册日期对其进行排序,并将其输出到CSV文件。提供的程序已经运行,在小输入下运行良好,但在大输入下故意失败。为了完成挑战,应该修改程序,使其能够像现在一样,在不耗尽内存的情况下解析和排序100000条记录,90MB的文件

在当前状态下,程序使用
file\u get\u contents()
,然后使用
json\u decode()
,然后使用
usort()
对项目进行排序。这在小样本数据文件中工作良好,但在大样本数据文件中不起作用-内存不足

输入文件 该文件为JSON格式,包含100000个对象。每个对象都有一个注册的属性(示例值
2017-12-25 04:55:33
),这就是CSV文件中记录的升序排序方式

我尝试的解决方案 目前,我已经使用了
halaxa/json机器
包,并且能够迭代文件中的每个对象。比如说

$people = \JsonMachine\JsonMachine::fromFile($fileName);
foreach ($people as $person) {
    // do something
}
将整个文件作为PHP数组读入内存不是一个选项,因为它占用了太多内存,所以到目前为止,我能想到的唯一解决方案是迭代文件中的每个对象,找到注册日期最早的人并打印出来。然后,再次迭代整个文件,找到下一个注册日期最早的人,并打印该人,等等

与此相关的大问题是嵌套循环:一个运行100000次的循环包含一个运行100000次的循环。这不是一个可行的解决方案,这是我做的最远的一次


如何解析、排序和打印成CSV,一个包含100000条记录的JSON文件?允许使用软件包/服务。

我最终将数据块导入MongoDB,然后以正确的顺序检索以打印

导入示例:

$collection=(新客户端($uri))->collection->people;
$collection->drop();
$people=JsonMachine::fromFile($fileName);
$chunk=[];
$chunkSize=5000;
$personNumber=0;
foreach($people作为$person){
$personNumber+=1;
$chunk[]=$person;
如果($personNumber%$chunkSize==0){//Chunk已满
$this->collection->insertMany($chunk);
$chunk=[];
}
}
//最后一个块没有填充到最大值,但我们仍然需要导入它
如果(计数($chunk)){
$this->collection->insertMany($chunk);
}
//创建索引以加快排序
$this->collection->createIndex(['registered'=>1]);
示例检索:

$results=$this->collection->find([]),
[
'排序'=>['registered'=>1],
]
);
//对于每个人。。。
foreach(结果为$person){
//对于每个属性。。。
foreach($people as$key=>$value){
如果($key!=''u id'){//,则无需包括新的MongoDB id
回显一些_csv_encode_函数($value)。',';
}
}
echo PHP_EOL;
}

我最终以块的形式导入到MongoDB中,然后以正确的顺序进行检索以进行打印

导入示例:

$collection=(新客户端($uri))->collection->people;
$collection->drop();
$people=JsonMachine::fromFile($fileName);
$chunk=[];
$chunkSize=5000;
$personNumber=0;
foreach($people作为$person){
$personNumber+=1;
$chunk[]=$person;
如果($personNumber%$chunkSize==0){//Chunk已满
$this->collection->insertMany($chunk);
$chunk=[];
}
}
//最后一个块没有填充到最大值,但我们仍然需要导入它
如果(计数($chunk)){
$this->collection->insertMany($chunk);
}
//创建索引以加快排序
$this->collection->createIndex(['registered'=>1]);
示例检索:

$results=$this->collection->find([]),
[
'排序'=>['registered'=>1],
]
);
//对于每个人。。。
foreach(结果为$person){
//对于每个属性。。。
foreach($people as$key=>$value){
如果($key!=''u id'){//,则无需包括新的MongoDB id
回显一些_csv_encode_函数($value)。',';
}
}
echo PHP_EOL;
}

我的意思是。。挑战的关键在于自己去做。。如果你在向别人寻求答案,你为什么还要这样做?我举个例子,你想要什么?Json写为CSV?@crayon因为。。。我不知道怎么做?与其放弃,我还想扩展我的知识,也许有些东西能帮上忙。@YvesLeBorg我正在使用一个不同的、类似的软件包,但我如何使用它来对项目进行排序?因为每个对象都需要根据
registed
属性进行排序。。挑战的关键在于自己去做。。如果你在向别人寻求答案,你为什么还要这样做?我举个例子,你想要什么?Json写为CSV?@crayon因为。。。我不知道怎么做?与其放弃,我还想扩展我的知识,也许有些东西能帮上忙。@YvesLeBorg我正在使用一个不同的、类似的软件包,但我如何使用它来对项目进行排序?因为每个对象都需要根据
registed
属性进行排序。