Comment peupler la mongoose avec un grand dataset

J’essaie de charger un catalogue de magasins dans MongoDb (2.2.2) à l’aide de Node.js (0.8.18) et de Mongoose (3.5.4), le tout sous Windows 7 64 bits. L’dataset contient environ 12 500 enregistrements. Chaque enregistrement de données est une chaîne JSON.

Ma dernière tentative ressemble à ceci:

var fs = require('fs'); var odir = process.cwd() + '/file_data/output_data/'; var mongoose = require('mongoose'); var Catalog = require('./models').Catalog; var conn = mongoose.connect('mongodb://127.0.0.1:27017/sc_store'); exports.main = function(callback){ var catalogArray = fs.readFileSync(odir + 'pc-out.json','utf8').split('\n'); var i = 0; Catalog.remove({}, function(err){ while(i < catalogArray.length){ new Catalog(JSON.parse(catalogArray[i])).save(function(err, doc){ if(err){ console.log(err); } else { i++; } }); if(i === catalogArray.length -1) return callback('database populated'); } }); }; 

J’ai eu beaucoup de problèmes à essayer de remplir la firebase database. Dans les scénarios précédents (et celui-ci), le noeud arrête le processeur et finit par manquer de mémoire. Notez que dans ce scénario, j’essaie de permettre à Mongoose de sauvegarder un enregistrement, puis de le parcourir au prochain enregistrement une fois que celui-ci a été sauvegardé.

Mais l’iterator à l’intérieur de la fonction de sauvegarde Mongoose n’est jamais incrémenté. De plus, il ne jette jamais aucune erreur. Mais si je mets l’iterator (i) en dehors de l’appel asynchrone à Mongoose, cela fonctionnera, à condition que le nombre d’enregistrements que je tente de charger ne soit pas trop important (j’ai réussi à charger 2 000 de cette façon).

Mes questions sont donc les suivantes: pourquoi l’iterator situé dans l’appel de sauvegarde Mongoose n’a-t-il jamais été incrémenté? Et, plus important encore, quel est le meilleur moyen de charger un jeu de données volumineux dans MongoDb à l’aide de Mongoose?

Rob

i est votre index vers où vous catalogArray données d’entrée dans catalogArray , mais vous essayez également de les utiliser pour garder une trace du nombre de celles qui ont été enregistrées, ce qui n’est pas possible. Essayez de les suivre séparément comme ceci:

 var i = 0; var saved = 0; Catalog.remove({}, function(err){ while(i < catalogArray.length){ new Catalog(JSON.parse(catalogArray[i])).save(function(err, doc){ saved++; if(err){ console.log(err); } else { if(saved === catalogArray.length) { return callback('database populated'); } } }); i++; } }); 

METTRE À JOUR

Si vous souhaitez append un contrôle de stream plus ssortingct au processus, vous pouvez utiliser la fonction forEachLimit du module async pour limiter le nombre d'opérations de save forEachLimit à ce que vous spécifiez. Par exemple, pour limiter cette save à une save exceptionnelle à la fois:

 Catalog.remove({}, function(err){ async.forEachLimit(catalogArray, 1, function (catalog, cb) { new Catalog(JSON.parse(catalog)).save(function (err, doc) { if (err) { console.log(err); } cb(err); }); }, function (err) { callback('database populated'); }); } 

Rob,

La réponse courte:

Vous avez créé une boucle infinie. Vous pensez de manière synchrone et avec le blocage, Javascript fonctionne de manière asynchrone et sans blocage. Ce que vous essayez de faire, c’est comme essayer de transformer directement le sentiment de faim en sandwich. Tu ne peux pas. Le plus proche est que vous utilisiez le sentiment de faim pour vous motiver à aller à la cuisine et à le préparer. N’essayez pas de bloquer le Javascript. Ça ne marchera pas. Maintenant, apprenez async.forEachLimit. Cela fonctionnera pour ce que vous voulez faire ici.

Vous devriez probablement examiner les modèles de conception asynchrones et comprendre ce que cela signifie à un niveau plus profond. Les rappels ne sont pas simplement une alternative pour renvoyer des valeurs. Ils sont fondamentalement différents dans le mode et le moment de leur exécution. Voici un bon aperçu: http://cs.brown.edu/courses/csci1680/f12/handouts/async.pdf

La réponse longue:

Il y a un problème sous-jacent ici, à savoir votre manque de compréhension de ce que signifient les entrées-sorties non bloquantes et asynchrone. Je ne suis pas sûr si vous vous lancez dans le développement de nœuds ou s’il s’agit d’un projet ponctuel, mais si vous envisagez de continuer à utiliser un nœud (ou tout autre langage asynchrone), vous devez alors comprendre la différence entre synchrone et asynchrone. modèles de conception, et quelles sont les motivations pour eux. C’est pourquoi vous avez une erreur de logique qui place l’incrément invariant de la boucle dans un rappel asynchrone créant une boucle infinie.

En sciences non informatiques, cela signifie que votre progression ne se produira jamais. La raison en est que Javascript exécute un seul bloc de code avant que tous les rappels asynchrones soient appelés. Donc, dans votre code, votre boucle fonctionnera encore et encore, sans jamais augmenter. Et, en arrière-plan, vous stockez le même document à plusieurs resockets. Chaque itération de la boucle commence à envoyer le document d’indice 0 à Mongo, le rappel ne peut pas être déclenché avant la fin de votre boucle et tous les autres codes en dehors de la boucle sont exécutés complètement. Donc, le rappel fait la queue. Cependant, votre boucle s’exécute à nouveau car i ++ n’est jamais exécuté (rappelez-vous que le rappel est mis en queue jusqu’à la fin du code), insérant à nouveau l’enregistrement 0, mettant en attente un autre rappel à exécuter APRÈS que votre boucle soit terminée. Cela se poursuit jusqu’à ce que votre mémoire soit remplie de rappels en attente pour informer votre boucle infinie que le document 0 a été inséré des millions de fois.

En général, il n’ya aucun moyen de bloquer JavaScript sans faire quelque chose de vraiment mauvais. Par exemple, il est primordial de mettre le feu à votre cuisine pour faire cuire des œufs pour le sandwich dont j’ai parlé dans la “réponse courte”.

Mon conseil est de profiter des libs comme async. https://github.com/caolan/async JohnnyHK l’a mentionné ici, et il a eu raison de le faire.