在 Nodejs 中解析大型 JSON 文件并独立处理每个对象

Posted

技术标签:

【中文标题】在 Nodejs 中解析大型 JSON 文件并独立处理每个对象【英文标题】:Parse large JSON file in Nodejs and handle each object independently 【发布时间】:2017-08-11 07:24:48 【问题描述】:

我需要在 Nodejs 中读取一个大的 JSON 文件(大约 630MB)并将每个对象插入到 MongoDB。

我在这里阅读了答案:Parse large JSON file in Nodejs。

但是,那里的答案是逐行处理 JSON 文件,而不是逐个对象处理它。因此,我仍然不知道如何从这个文件中获取一个对象并对其进行操作。

我的 JSON 文件中有大约 100,000 个此类对象。

数据格式:

[
  
    "id": "0000000",
    "name": "Donna Blak",
    "livingSuburb": "Tingalpa",
    "age": 53,
    "nearestHospital": "Royal Children's Hospital",
    "treatments": 
        "19890803": 
            "medicine": "Stomach flu B",
            "disease": "Stomach flu"
        ,
        "19740112": 
            "medicine": "Progeria C",
            "disease": "Progeria"
        ,
        "19830206": 
            "medicine": "Poliomyelitis B",
            "disease": "Poliomyelitis"
        
    ,
    "class": "patient"
  ,
 ...
]

干杯,

亚历克斯

【问题讨论】:

【参考方案1】:

有一个名为 'stream-json' 的不错的模块可以满足您的需求。

它可以解析远远超过可用内存的 JSON 文件。

StreamArray 处理一个常见的用例:一个由相对较小的对象组成的巨大数组,类似于 Django 生成的数据库转储。它单独流式传输数组组件,负责自动组装它们。

这是一个非常基本的例子:

const StreamArray = require('stream-json/streamers/StreamArray');
const path = require('path');
const fs = require('fs');

const jsonStream = StreamArray.withParser();

//You'll get json objects here
//Key is an array-index here
jsonStream.on('data', (key, value) => 
    console.log(key, value);
);

jsonStream.on('end', () => 
    console.log('All done');
);

const filename = path.join(__dirname, 'sample.json');
fs.createReadStream(filename).pipe(jsonStream.input);

如果您想做一些更复杂的事情,例如依次处理一个对象(保持顺序)并为每个对象应用一些异步操作,然后您可以像这样执行自定义 Writeable 流:

const StreamArray = require('stream-json/streamers/StreamArray');
const Writable = require('stream');
const path = require('path');
const fs = require('fs');

const fileStream = fs.createReadStream(path.join(__dirname, 'sample.json'));
const jsonStream = StreamArray.withParser();

const processingStream = new Writable(
    write(key, value, encoding, callback) 
        //Save to mongo or do any other async actions

        setTimeout(() => 
            console.log(value);
            //Next record will be read only current one is fully processed
            callback();
        , 1000);
    ,
    //Don't skip this, as we need to operate with objects, not buffers
    objectMode: true
);

//Pipe the streams as follows
fileStream.pipe(jsonStream.input);
jsonStream.pipe(processingStream);

//So we're waiting for the 'finish' event when everything is done.
processingStream.on('finish', () => console.log('All done'));

请注意: 上面的示例针对“stream-json@1.1.3”进行了测试。对于某些以前的版本(大概是 1.0.0 之前的版本),您可能必须:

const StreamArray = require('stream-json/utils/StreamArray');

然后

const jsonStream = StreamArray.make();

【讨论】:

Stream-json 必须是迄今为止最好的 json 流阅读器。它使我免于创建自己的流和挑选每个对象。感谢您的回答。我遇到了同样的问题,内存不足,唯一的解决方案是一次流式传输每个对象。 @LixingLiang 将单个文件拆分为多个文件并并行处理,这样可以提高效率。瓶颈可能是读取文件时的 IO 操作。 这些例子似乎已经过时了。我遇到了 require 错误并更改为 const StreamArray = require('stream-json/streamers/StreamArray') 但随后出现错误 TypeError: Cannot read property 'on' of undefined. @PrestonDocks 该软件包于 2018 年更新,主要版本跳转(更好的性能,更多的实用程序)。要么使用以前的主要版本,要么阅读新文档并相应地更新您的代码。 @PrestonDocks,更新了答案,你介意看看。

以上是关于在 Nodejs 中解析大型 JSON 文件并独立处理每个对象的主要内容,如果未能解决你的问题,请参考以下文章

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件

如何发布使用 GSON 解析大型 json 文件的进度

在 NodeJS 中解析 JSON 对象数组

解析大型 JSON 文件 [重复]