web-dev-qa-db-fra.com

Analyser un gros fichier JSON dans Nodejs et gérer chaque objet indépendamment

J'ai besoin de lire un gros fichier JSON (environ 630 Mo) dans Nodejs et d'insérer chaque objet dans MongoDB.

J'ai lu la réponse ici: Analyser un gros fichier JSON dans Nodejs .

Cependant, les réponses gèrent le fichier JSON ligne par ligne, au lieu de le gérer objet par objet. Ainsi, je ne sais toujours pas comment obtenir un objet de ce fichier et le faire fonctionner.

J'ai environ 100 000 objets de ce type dans mon fichier JSON.

Format des données:

[
  {
    "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"
  },
 ...
]

À votre santé,

Alex

19
Lixing Liang

Il y a un module Nice nommé 'stream-json' qui fait exactement ce que vous voulez.

Il peut analyser les fichiers JSON dépassant de loin la mémoire disponible.

et

StreamArray gère un cas d'utilisation fréquent: un vaste éventail d'objets relativement petits similaires aux vidages de base de données produits par Django. Il diffuse les composants de la baie individuellement en prenant soin de les assembler automatiquement.

Voici un exemple très basique:

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

Si vous souhaitez faire quelque chose de plus complexe, par exemple traiter un objet après un autre séquentiellement (en gardant l'ordre) et appliquer des opérations asynchrones pour chacun d'eux, vous pouvez faire le flux d'écriture personnalisé comme ceci:

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

Veuillez noter: Les exemples ci-dessus sont testés pour '[email protected]'. Pour certaines versions précédentes (vraisemblablement antérieures à 1.0.0), vous devrez peut-être:

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

et alors

const jsonStream = StreamArray.make();

30
Antonio Narkevich