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 вместо теста