node.js - 以内存高效的方式从 JSON 中过滤无效的 JSON 值
我们有一些我们正在尝试解析的错误 JSON。不幸的是,它不是有效的 JSON,因为它在负载中返回未加引号的 NaN。
我们正在从已经过时很久的 request 库切换到 axios。这似乎使我们当前修复此负载的方法的内存使用量翻倍,但我们的环境内存受限。文件大小为 19MB,我们的限制是 50MB。我推测某些与正则表达式/解析相关的操作导致在内存中又生成了 JSON 的另一个副本,此外 axios 自身还在尝试进行解析。
我们正在使用一个围绕 axios 的封装,因此直接与它交互是有限的。我必须重新实现封装的部分内容才能访问它,而且它是一个外部内部库。
我知道我们试图保留的键,所以实际上丢弃其余结构而不是处理 NaN 更可取。
我们想要的结构看起来像 DataUsages[]
export interface DataUsages {
dataUsageId: string;
dataUsageName: string;
}
我们得到的结构在数组的对象中有额外的项目,我们根本不关心 "dataUsageDownstreamUsages",而且这个键可以被丢弃,也确实被丢弃了。
[
{
"dataUsageId": "42",
"dataUsageName": "myname",
"dataUsageDownstreamUsages": [NaN]
}
]
当前
这是我们目前的方法
const reg1 = /\[NaN]|NaN/gm
const parsed: EDMDataUsages[] = JSON.parse(
requireNonNullish(response.body, 'body').replace(reg1, '""').replace(/NAN/gm, ''),
)
流式 JSON
现在我正在考虑为此使用 stream-json。
如果我使用解析器,它会中止,大概是在遇到 NaN 时。所以我在看 disassembler,但我不明白如何用它来做这件事。
const read = new Readable()
read.push(requireNonNullish(response.body, 'body'))
read.push(null)
const pipeline = chain([read, disassembler(), pick({ filter: 'data' }), data => this.log.trace('data', data)])
pipeline.on('data', data => this.log.trace('filter', data))
显然这段代码不完整。
其他库也是可以的。请提供一个完整的示例。
答案#1
好,首先让我们创建一个假的数据
function genreateFakeData() {
const payload = { res: [] }
const mock = {
"dataUsageId": "42",
"dataUsageName": "myname",
"dataUsageDownstreamUsages": [NaN]
}
let totalFileSize = 0;
const fileSize = 19;
const SIZE_IN_BYTES = JSON.stringify(mock).length;
const SIZE_IN_MB = SIZE_IN_BYTES / 1024 / 1024;
while (totalFileSize < fileSize) {
totalFileSize += SIZE_IN_MB;
payload.res.push(mock);
}
fs.appendFileSync('fake.json', JSON.stringify(payload));
}
那么让我们测试一下这是不是文件的正确大小
> ls -ltrh | grep fake
-rw-r--r-- 1 naor.tedgi staff 19M Jun 15 09:34 fake.json
让我们在堆内存限制下运行节点应用,并更改原始响应
node --max-old-space-size=50 index.jsindex.js
const stream = require('stream');
const fs = require('fs');
const data = JSON.parse(fs.readFileSync('fake.json',{encoding:'utf8', flag:'r'}));
data.res.forEach(entry=>{
delete entry.dataUsageDownstreamUsages
})
console.log(data)
