web-dev-qa-db-fra.com

Mongoose - RangeError: taille maximale de la pile d'appels dépassée

J'essaie d'insérer en vrac des documents dans MongoDB (donc en contournant Mongoose et en utilisant le pilote natif à la place car Mongoose ne prend pas en charge l'insertion en bloc d'un tableau de documents). La raison pour laquelle je fais cela est d'améliorer la vitesse d'écriture.

Je reçois l'erreur "RangeError: Maximum Call Stack Size Exceeded" sur console.log (err) dans le code ci-dessous:

function _fillResponses(globalSurvey, optionsToSelectRegular, optionsToSelectPiped, responseIds, callback) {
  Response.find({'_id': {$in: responseIds}}).exec(function(err, responses) {
    if (err) { return callback(err); }

    if (globalSurvey.questions.length) {
      responses.forEach(function(response) {
        console.log("Filling response: " + response._id);
        response.answers = [];
        globalAnswers = {};
        globalSurvey.questions.forEach(function(question) {
          ans = _getAnswer(question, optionsToSelectRegular, optionsToSelectPiped, response);
          globalAnswers[question._id] = ans;
          response.answers.Push(ans);
        });
      });
      Response.collection.insert(responses, function(err, responsesResult) {
        console.log(err);
        callback()
      });
    } else {
        callback();
      }
  });
} 

Si similaire à: https://stackoverflow.com/questions/24356859/mongoose-maximum-call-stack-size-exceeded

Peut-être que c'est quelque chose au sujet du format du tableau de réponses que Mongoose retourne qui signifie que je ne peux pas insérer directement en utilisant MongoDB nativement? J'ai essayé .toJSON () sur chaque réponse mais pas de chance.

J'obtiens toujours l'erreur même avec une très petite quantité de données mais en boucle et en appelant la sauvegarde Mongoose sur chaque document fonctionne correctement.

EDIT: Je pense que cela est lié à ce problème: http://howtosjava.blogspot.com.au/2012/05/nodejs-mongoose-rangeerror-maximum-call.html

Mon schéma de réponses est le suivant:

var ResponseSchema = new Schema({
  user: {
    type: Schema.ObjectId,
    ref: 'User'
  },
  randomUUID: String,
  status: String,
  submitted: Date,
  initialEmailId: String,
  survey: String,
  answers: [AnswerSchema]
}); 

Ainsi, les réponses sont un sous-document dans les réponses. Je ne sais pas comment y remédier ...

28
Andrew

J'avais ce même problème et j'ai commencé à fouiller le code source de la mangouste (version 3.8.14). Finalement, cela m'a conduit à cette ligne

  • mangouste/node_modules/mongodb/lib/mongodb/collection/core.js -> insert (...) -> insertWithWriteCommands (...) ->
  • mangouste/node_modules/mongodb/lib/mongodb/collection/batch/order.js -> bulk.insert (docs [i]) -> addToOperationsList (...) -> bson.calculateObjectSize (document, false);

    var bsonSize = bson.calculateObjectSize (document, faux);

Apparemment, cela appelle BSON.calculateObjectSize, qui appelle CalculateObjectSize qui revient ensuite à l'infini. Je n'ai pas pu creuser aussi loin dans la cause, mais j'ai pensé que cela pouvait avoir quelque chose à voir avec les fonctions de liaison de l'enveloppe mangouste au schéma. Étant donné que j'insérais des données brutes dans mongoDB, une fois que j'ai décidé de changer l'insertion en masse dans mangouste en un objet javascript standard, le problème a disparu et les insertions en masse se sont produites correctement. Vous pourriez peut-être faire quelque chose de similaire.

Essentiellement, mon code est passé de

//EDIT: mongoose.model needs lowercase 'm' for getter method

var myModel = mongoose.model('MyCollection');
var toInsert = myModel();
var array = [toInsert];
myModel.collection.insert(array, {}, function(err, docs) {});

à

//EDIT: mongoose.model needs lowercase 'm' for getter method

var myModel = mongoose.model('MyCollection');
var toInsert = { //stuff in here 
   name: 'john',
   date: new Date()
};
var array = [toInsert];
myModel.collection.insert(array, {}, function(err, docs) {});
30
rocketegg

Confirmé, mais pas un bug. Model.collection.insert() contourne Mongoose et vous dites donc au pilote de nœud d'insérer un objet qui contient des éléments internes de mangouste comme $__, etc. Le débordement de pile est probablement dû au fait que bson essaie de calculer la taille de un objet qui se référence indirectement.

Pour faire court, utilisez Document.toObject(), c'est pour ça: http://mongoosejs.com/docs/api.html#document_Document-toObject

Response.find({}).exec(function(err, responses) {
  if (err) { 
    return callback(err); 
  }

  if (true) {
    var toInsert = [];
    responses.forEach(function(response) {
      console.log("Filling response: " + response._id);
      response.answers = [];
      [{ name: 'test' }].forEach(function(ans) {
        response.answers.Push(ans);
      });
      toInsert.Push(response.toObject());
    });
    Response.collection.insert(toInsert, function(err, responsesResult) {
      console.log(err);
    });
  } else {
      callback();
    }
});

De plus, le code que vous avez spécifié ne fonctionnera pas même si vous corrigez le débordement de pile. Puisque vous essayez de insert() documents qui sont déjà dans la base de données, toutes les insertions échoueront en raison de conflits _id. Vous seriez vraiment beaucoup mieux en utilisant simplement un stream () pour lire les résultats un à la fois, puis save() dans la base de données.

18
Valeri Karpov

J'ai rencontré un problème similaire.

//manyvalues is array of objects
schema.methods.somemethod = function(manyvalues,callback) {
    this.model(collection).collection.insertMany(manyvalues,callback);
}

Mais cela a provoqué une erreur [RangeError: la taille maximale de la pile d'appels a été dépassée]. J'ai donc créé un nouveau modèle à partir de plusieurs valeurs et l'ai utilisé comme ci-dessous et cela a fonctionné.

schema.methods.somemethod = function(manyvalues,callback){
     var list = JSON.parse(JSON.stringify(manyvalues));//created a new object.
     this.model(collection).collection.insertMany(list,callback);
}

Le problème peut être provoqué si plusieurs valeurs sont modifiées en interne.

2
alex.jangam

Cela se produit également en cas de duplication de _id valeur. La plupart des situations consistent à créer un nouvel enregistrement à partir d'un enregistrement existant.

Suppression du _id et en insérant l'enregistrement et en laissant Mongoose/MongoDb se charger de la création de l'identifiant.

1
Naveen Paul

les gars! J'ai fait face à cette étrange erreur aujourd'hui. Cela s'est produit parce que j'avais un schéma avec les propriétés ref et que j'ai essayé de transmettre create/update tout le document associé. J'ai changé l'argument en _id seulement et cela a fait l'affaire. Fonctionne comme un charme. J'ai trouvé la réponse ici (faites défiler jusqu'à February 21, 2013, 8:05 pm gustavohenke commentaire).

1
18augst

Vérifiez les références circulaires dans l'objet réponses. J'ai rencontré un problème similaire en raison de références circulaires.

0
Manzoor Samad