Mongoose - RangeError:超出最大调用堆栈大小

新手上路,请多包涵

我正在尝试将文档批量插入 MongoDB(因此绕过 Mongoose 并使用本机驱动程序代替,因为 Mongoose 不支持批量插入文档数组)。我这样做的原因是为了提高写作速度。

我在以下代码的 console.log(err) 收到错误“RangeError:超出最大调用堆栈大小”:

 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/questions/24356859/mongoose-maximum-call-stack-size-exceeded

也许是关于 Mongoose 返回的响应数组格式的问题,这意味着我不能直接使用 MongoDB 本机插入?我在每个响应上都尝试了 .toJSON() 但没有成功。

即使数据量非常小,我仍然会收到错误消息,但循环遍历并在每个文档上调用 Mongoose 保存都可以正常工作。

编辑:我认为这与这个问题有关: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]
});

因此,答案是响应中的子文档。不知道如何解决它……

原文由 Andrew 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 283
2 个回答

我遇到了同样的问题,于是我开始研究 mongoose 源代码(3.8.14 版)。最终它把我带到了这条线

  • mongoose/node_modules/mongodb/lib/mongodb/collection/core.js -> 插入(…) -> 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,然后无限递归。我无法深入了解导致它的原因,但认为它可能与模式的 mongoose 包装器绑定函数有关。由于我将原始数据插入到 mongoDB 中,一旦我决定将 mongoose 中的批量插入更改为标准的 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) {});

原文由 rocketegg 发布,翻译遵循 CC BY-SA 3.0 许可协议

已确认,但不是错误。 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() 将它们放回数据库中真的会好得多。

原文由 Valeri Karpov 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题