2014-06-28 19 views
23

Tôi đang cố chèn hàng loạt tài liệu vào MongoDB (vì vậy bỏ qua Mongoose và sử dụng trình điều khiển gốc thay vì Mongoose không hỗ trợ chèn hàng loạt tài liệu). Lý do tôi làm điều này là cải thiện tốc độ viết.Mongoose - RangeError: Kích thước ngăn xếp tối đa vượt quá

Tôi nhận được lỗi "RangeError: Tối đa Call Stack Kích Exceeded" tại console.log (err) trong mã dưới đây:

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

Vì vậy, tương tự như: https://stackoverflow.com/questions/24356859/mongoose-maximum-call-stack-size-exceeded

Có lẽ đó là một cái gì đó về định dạng của mảng phản hồi mà Mongoose trả về có nghĩa là tôi không thể chèn trực tiếp bằng MongoDB một cách tự nhiên? Tôi đã thử .toJSON() trên mỗi câu trả lời nhưng không may mắn.

Tôi vẫn nhận được lỗi ngay cả với một lượng dữ liệu rất nhỏ nhưng lặp lại và gọi Mongoose lưu trên mỗi tài liệu riêng lẻ hoạt động tốt.

EDIT: Tôi nghĩ rằng nó có liên quan đến vấn đề này: http://howtosjava.blogspot.com.au/2012/05/nodejs-mongoose-rangeerror-maximum-call.html

schema của tôi cho câu trả lời là:

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

Vì vậy, câu trả lời là một tiểu tài liệu trong câu trả lời. Không chắc chắn cách khắc phục nó mặc dù ....

+0

Có lẽ không liên quan, nhưng 'callback()' được gọi hai lần nếu 'globalSurvey.questions' không trống. Gọi 'callback()' cuối cùng trong câu lệnh 'else':'} else {callback(); } '. –

+0

Cảm ơn - yep đồng ý nhưng nghĩ rằng nó không liên quan .... đã không có quá khứ chèn chưa. – Andrew

+0

Tôi đã chỉnh sửa để khắc phục sự cố đó. – Andrew

Trả lời

28

Tôi đã gặp vấn đề tương tự này và tôi bắt đầu tìm kiếm thông qua mã nguồn mongoose (phiên bản 3.8.14). Cuối cùng nó dẫn tôi đến dòng này trong vòng

  • mongoose/node_modules/MongoDB/lib/MongoDB/bộ sưu tập/core.js ->chèn (...) ->insertWithWriteCommands (...) - >
  • mongoose/node_modules/MongoDB/lib/MongoDB/bộ sưu tập/mẻ/ordered.js ->bulk.insert (tài liệu [i]) ->addToOperationsList (...) ->bson. calculateObjectSize (tài liệu, sai);

    var bsonSize = bson.calculateObjectSize (tài liệu, sai);

Rõ ràng, điều này gọi BSON.calculateObjectSize, gọi là calculateObjectSize mà sau đó vô hạn đệ quy. Tôi đã không thể đào sâu đến mức những gì gây ra nó, nhưng đã tìm ra rằng nó có thể liên quan đến các hàm ràng buộc mongoose bao bọc cho Lược đồ. Vì tôi đã chèn dữ liệu thô vào mongoDB, một khi tôi quyết định thay đổi chèn hàng loạt trong mongoose thành đối tượng javascript chuẩn, vấn đề đã biến mất và chèn hàng loạt diễn ra chính xác. Bạn có thể làm điều tương tự.

Về cơ bản, mã của tôi đi từ

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

Chỉ cần thêm một số làm rõ cho câu trả lời này, vấn đề có thể được giải quyết bằng cách: 1. không sử dụng một ví dụ lược đồ cho chèn số 2: thay vào đó, sử dụng một đối tượng JSON cũ đơn giản. – adrichman

+0

Nên được chấp nhận trả lời, giải quyết vấn đề của tôi! Cảm ơn! – ComethTheNerd

15

xác nhận, nhưng không phải là một lỗi. Model.collection.insert() bỏ qua Mongoose và vì vậy bạn đang yêu cầu trình điều khiển nút chèn đối tượng chứa nội bộ mongoose như $__, v.v.Stack overflow có lẽ là vì bson đang cố tính toán kích thước của một đối tượng tham chiếu một cách gián tiếp.

câu chuyện dài ngắn, sử dụng Document.toObject(), đó là những gì nó cho: 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(); 
    } 
}); 

Ngoài ra, các mã mà bạn chỉ định sẽ không làm việc ngay cả khi bạn khắc phục stack overflow. Vì bạn đang cố gắng để insert() tài liệu đã có trong cơ sở dữ liệu, tất cả các chèn sẽ thất bại vì các xung đột _id. Bạn thực sự sẽ tốt hơn rất nhiều khi chỉ sử dụng luồng() để đọc từng kết quả và sau đó save() chúng trở lại vào db.

+0

Cảm ơn Valeri! Tham khảo: https://github.com/LearnBoost/mongoose/issues/1961#event-242694964 – nottinhill

+0

Tôi gặp phải điều tương tự khi sử dụng chèn hàng loạt. Nó hoạt động như một say mê. cảm ơn bạn. tại sao sử dụng đối tượng mongoose trong chèn số lượng lớn sẽ gây ra vấn đề? – zach

-1

Tôi đã có một vấn đề tương tự, người ta rằng tôi đã truy vấn một lĩnh vực chưa từng tồn tại trong lược đồ bằng cách sử dụng $ ne (nhà khai thác truy vấn khác có thể có một vấn đề tương tự)

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

Trong ví dụ này ở trên tôi đang thử nghiệm cho test2 thay vì kiểm tra

1

guys! Tôi đã phải đối mặt với lỗi kỳ lạ ngày hôm nay. Điều đó xảy ra vì tôi có một Schema với các thuộc tính ref và cố gắng chuyển vào tài liệu có liên quan đến create/update. Tôi đã thay đổi đối số thành chỉ _id và điều đó đã thực hiện mẹo. Làm việc như một say mê. Tôi đã tìm thấy câu trả lời here (cuộn xuống February 21, 2013, 8:05 pm gustavohenke nhận xét).

+0

Cảm ơn, đây chắc chắn là vấn đề của tôi, không giống như một số vấn đề khác ở đây. –

1

Tôi đã gặp phải sự cố tương tự.

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

Nhưng điều này gây ra lỗi [RangeError: kích thước gọi stack tối đa vượt quá]. Vì vậy, tôi đã tạo mô hình mới từ nhiều giá trị và sử dụng mô hình như dưới đây và nó hoạt động.

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

Vấn đề có thể được gây ra nếu manyvalues ​​ được thay đổi trong nội bộ.

1

Điều này cũng xảy ra nếu có sự trùng lặp của giá trị _id. Hầu hết các tình huống sẽ là khi bạn có thể tạo một bản ghi mới từ một bản ghi hiện có.

Xóa _id và chèn bản ghi và để Mongoose/MongoDb quản lý việc tạo id.

Các vấn đề liên quan