node.js - filtrera dåliga json-värden från json på ett minneseffektivt sätt


Vi har lite dålig JSON som vi försöker tolka. Tyvärr är det inte giltig JSON eftersom det returnerar o-omslutna NaN-värden i payloaden.

Vi byter från det länge föråldrade request-biblioteket till axios. Detta verkar ha fördubblat vårt minnesanvändande jämfört med vårt nuvarande sätt att fixa denna payload, men vår miljö har begränsat minne. Filen är 19 MB, vår begränsning är 50 MB. Jag antar att något som har med regexarna/parsing att göra skapar ytterligare en kopia av jsonen i minnet, utöver den parsing som axios försöker göra.

Vi använder ett wrapper runt axios, så direkt interaktion med det är begränsad. Jag skulle behöva implementera om delar av wrappern för att komma åt det och det är ett externt internt bibliotek.

Jag vet vilka nycklar vi försöker behålla, så att bara kasta resten av strukturen istället för att hantera NaN är faktiskt att föredra.

Strukturen vi vill ha ser ut som DataUsages[]

export interface DataUsages {
    dataUsageId: string;
    dataUsageName: string;
}

Strukturen vi får har ytterligare objekt i arrayen, vi bryr oss inte alls om "dataUsageDownstreamUsages", och den nyckeln kan och håller på att kastas bort

[
  {
    "dataUsageId": "42",
    "dataUsageName": "myname",
    "dataUsageDownstreamUsages": [NaN]
  }
]

nuvarande

Detta är vår nuvarande metod

      const reg1 = /\[NaN]|NaN/gm
      const parsed: EDMDataUsages[] = JSON.parse(
        requireNonNullish(response.body, 'body').replace(reg1, '""').replace(/NAN/gm, ''),
      )   

ström-json

Just nu tittar jag på att använda stream-json för detta.

Om jag använder parsern kraschar den, antagligen när den når en NaN. Så jag tittar på disassemblern men jag förstår inte hur man gör det med den.

  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))

uppenbarligen är denna kod inte komplett.

Andra bibliotek är acceptabla. Vänligen ge ett komplett exempel.

Svar #1

okej först och främst låt oss skapa falska data

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));
}

då låt oss testa om detta är rätt storlek på filen

> ls -ltrh | grep fake
-rw-r--r--   1 naor.tedgi  staff    19M Jun 15 09:34 fake.json

låt oss köra node-appen under heap-begränsningen och förändra det ursprungliga svaret

node --max-old-space-size=50 index.js

index.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)