【问题标题】:Mongoose - RangeError: Maximum Call Stack Size ExceededMongoose - RangeError:超过最大调用堆栈大小
【发布时间】:2014-08-19 10:07:54
【问题描述】:

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

我在下面的代码中的 console.log(err) 处收到错误“RangeError: Maximum Call Stack Size Exceeded”:

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

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

【问题讨论】:

  • 可能不相关,但如果globalSurvey.questions 不为空,则会调用两次callback()。在else 语句中调用最后一个callback()} else { callback(); }
  • 谢谢 - 是的,同意,但认为这无关......尚未通过插入。
  • 我已编辑以解决该问题。

标签: javascript node.js mongodb mongoose


【解决方案1】:

我遇到了同样的问题,我开始研究 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。我无法深入挖掘导致它的原因,但认为它可能与 Schema 的 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) {});

【讨论】:

  • 只是为了澄清这个答案,问题可以通过以下方式解决:1.不要为批量插入使用模式实例 2:而是使用普通的旧 JSON 对象。跨度>
  • 应该被接受的答案,解决了我的问题!谢谢!
【解决方案2】:

已确认,但不是错误。 Model.collection.insert() 绕过 Mongoose,因此您告诉节点驱动程序插入一个包含 $__ 等 mongoose 内部结构的对象。堆栈溢出可能是因为 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() 将它们返回到数据库中,你真的会好得多。

【讨论】:

【解决方案3】:

我遇到了类似的问题,就是我正在使用 $ne 查询架构中不存在的字段(其他查询运算符可能有类似的问题)

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

在上面的示例中,我正在测试 test2 而不是 test

【讨论】:

    【解决方案4】:

    伙计们!我今天遇到了那个奇怪的错误。发生这种情况是因为我有一个带有ref 属性的架构并试图传入create/update 整个相关文档。我只将参数更改为_id,就成功了。奇迹般有效。我找到了答案here(向下滚动到February 21, 2013, 8:05 pm gustavohenke 评论)。

    【讨论】:

    • 谢谢,这绝对是我的问题,不像这里的其他一些问题。
    • 这应该是比从猫鼬旋转的有效答案。谢谢大佬!
    • 谢谢,克隆多个数据并将整个文档更改为仅 _id 时遇到完全相同的问题。
    • 我还看到了相反的情况,文档中的 _id 字段导致了这个循环。我补充说为了获得更好的类型检查,删除解决了我的问题。 YMMV :)
    【解决方案5】:

    我也遇到过类似的问题。

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

    但这会导致错误[RangeError: 超出最大调用堆栈大小]。 因此,我从 manyvalues 创建了新模型,并按如下方式使用它并且它起作用了。

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

    如果manyvalues在内部发生变化,可能会导致问题。

    【讨论】:

    • 太好了,它对我有帮助 - 在我的情况下,问题是我试图 findOneAndUpdate 使用包含转换为 ES2016 类实例的打字稿类的对象(所以很可能只使用类实例也会出现问题)。
    【解决方案6】:

    如果_id 值重复,也会发生这种情况。大多数情况是您可以从现有记录创建新记录。

    删除 _id 并插入记录并让 Mongoose/MongoDb 负责创建 id。

    【讨论】:

      【解决方案7】:

      检查响应对象中的循环引用。由于循环引用,我遇到了类似的问题。

      【讨论】:

        猜你喜欢
        • 2012-05-27
        • 2020-04-14
        • 2019-04-25
        • 2013-08-18
        • 2018-07-29
        • 2021-10-24
        • 2018-02-06
        相关资源
        最近更新 更多