Mongoose - RangeError: максимальный размер стека вызовов превышен

Я пытаюсь объединить вставки документов в MongoDB (поэтому в обход Mongoose и вместо этого использовать собственный драйвер, поскольку Mongoose не поддерживает массовую вставку массива документов). Причина, по которой я делаю это, - улучшить скорость написания.

Я получаю ошибку "RangeError: максимальный размер стека вызовов превышен" на console.log(err) в коде ниже:

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

Аналогично: https://stackoverflow.com/info/24356859/mongoose-maximum-call-stack-size-exceeded

Возможно, это что-то вроде формата массива ответов, который возвращает Mongoose, что означает, что я не могу напрямую вставить с помощью MongoDB изначально? Я пробовал.toJSON() для каждого ответа, но не повезло.

Я все еще получаю ошибку даже с очень небольшим количеством данных, но цикл и вызов Mongoose save на каждом документе индивидуально работает нормально.

EDIT: Я думаю, что это связано с этой проблемой: http://howtosjava.blogspot.com.au/2012/05/nodejs-mongoose-rangeerror-maximum-call.html

Моя схема ответов:

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

Таким образом, ответы являются суб-документами в ответах. Не уверен, как это исправить, хотя....

Ответы

Ответ 1

У меня была такая же проблема, и я начал копаться в исходном коде Mongoose (версия 3.8.14). В конце концов это привело меня к этой линии внутри

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

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

По-видимому, это вызывает BSON.calculateObjectSize, который вызывает calculateObjectSize, который затем бесконечно рекурсирует. Я не смог проскочить до того, что вызвало это, но подумал, что это может иметь какое-то отношение к функциям привязки оболочки мангуста к Схеме. Поскольку я вставлял необработанные данные в mongoDB, как только я решил изменить объемную вставку в мангусте на стандартный объект javascript, проблема исчезла, а объемные вставки произошли правильно. Возможно, вы сможете сделать что-то подобное.

По сути, мой код

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

Ответ 2

Подтверждено, но не ошибка. Model.collection.insert() обходит Mongoose и поэтому вы Model.collection.insert() драйверу узла вставить объект, содержащий внутренние элементы мангуста, такие как $__ и т.д. Переполнение стека, вероятно, связано с тем, что bson пытается вычислить размер объекта, который ссылается косвенно.

Короче говоря, используйте Document.toObject(), что его для: 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();
    }
});

Кроме того, указанный вами код не будет работать, даже если вы исправите переполнение стека. Поскольку вы пытаетесь insert() документы, которые уже находятся в базе данных, все вставки будут терпеть неудачу из-за конфликтов _id. Вам было бы намного лучше использовать stream() для чтения результатов по одному, а затем save() их обратно в db.

Ответ 3

Я столкнулся с подобной проблемой.

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

Но это вызвало ошибку [RangeError: Максимальный размер стека вызовов]. Поэтому я создал новую модель из многих значений и использовал ее, как показано ниже, и она сработала.

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

Проблема может быть вызвана, если многие значения будут изменены внутренне.

Ответ 4

ребята! Сегодня я столкнулся с этой странной ошибкой. Это случилось из - за меня была схема с ref свойствами и попытался передать в create/update весь связанный с ним документ. Я изменил аргумент только на _id и это сделало трюк. Работает как шарм. Я нашел ответ здесь (прокрутите вниз до February 21, 2013, 8:05 pm gustavohenke comment).

Ответ 5

Это также происходит, если существует дублирование значения _id. В большинстве случаев вы можете создать новую запись из существующей записи.

Удаление _id и вставки записи и позволяя Mongoose/MongoDb заботиться о создании ид.

Ответ 6

Проверьте наличие циклических ссылок в объекте ответов. Столкнулся с подобной проблемой из-за циркулярных ссылок.

Ответ 7

У меня была аналогичная проблема: я запрашивал поле, которое не существовало в схеме, используя $ ne (у других операторов запроса может быть аналогичная проблема)

var TestSchema = new Schema({
  test:[]
});
...
models.Test.findOne({"test2": {$ne: "t"} })...

В приведенном выше примере я тестирую test2 вместо теста