gpt4 book ai didi

JavaScript 堆内存不足 - 插入 mongodb 时出错

转载 作者:可可西里 更新时间:2023-11-01 09:38:11 24 4
gpt4 key购买 nike

我想在 MongoDB 中插入 1500000 个文档。首先,我查询一个数据库并从那里获得 15000 名讲师的列表,并且我想为每个讲师插入 100 门类(class)。

我运行两个循环:首先它遍历所有讲师,其次,在每次迭代中它将为该 id 插入 100 个文档,如下面的代码所示:

const instructors = await Instructor.find();
//const insrtuctor contains 15000 instructor
instructors.forEach((insructor) => {
for(let i=0; i<=10; i++) {
const course = new Course({
title: faker.lorem.sentence(),
description: faker.lorem.paragraph(),
author: insructor._id,
prise: Math.floor(Math.random()*11),
isPublished: 'true',
tags: ["java", "Nodejs", "javascript"]
});
course.save().then(result => {
console.log(result._id);
Instructor.findByIdAndUpdate(insructor._id, { $push: { courses: course._id } })
.then(insructor => {
console.log(`Instructor Id : ${insructor._id} add Course : ${i} `);
}).catch(err => next(err));
console.log(`Instructor id: ${ insructor._id } add Course: ${i}`)
}).catch(err => console.log(err));
}
});

这是我的 package.json 文件,我把我在互联网上找到的东西放在这里:

{
"scripts": {
"start": "nodemon app.js",
"fix-memory-limit": "cross-env LIMIT=2048 increase-memory-limit"
},
"devDependencies": {
"cross-env": "^5.2.0",
"faker": "^4.1.0",
"increase-memory-limit": "^1.0.6",
}
}

这是我的类(class)模型定义

const mongoose = require('mongoose');

const Course = mongoose.model('courses', new mongoose.Schema({

title: {
type: String,
required: true,
minlength: 3
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'instructor'
},
description: {
type: String,
required: true,
minlength: 5
},
ratings: [{
user: {
type: mongoose.Schema.Types.ObjectId,
ref: 'users',
required: true,
unique: true
},
rating: {
type: Number,
required: true,
min: 0,
max: 5
},
description: {
type: String,
required: true,
minlength: 5
}
}],
tags: [String],
rating: {
type: Number,
min: 0,
default: 0
},
ratedBy: {
type: Number,
min: 0,
default: 0
},
prise: {
type: Number,
required: function() { this.isPublished },
min: 0
},
isPublished: {
type: Boolean,
default: false
}
}));

module.exports = Course;

最佳答案

对于大量数据,您必须使用游标

想法处理 文档尽快 当你从数据库中得到一个 时。

就像您要求 db 提供指导db 发回小批量,然后您对该批处理进行操作并处理它们< strong>until reach 所有批处理的结束

否则 await Instructor.find()加载所有数据 到内存 并使用您不需要的 Mongoose 方法填充实例

即使 await Instructor.find().lean() 也不会带来内存优势。

游标是mongodb 的功能,当您在集合上find 时。

使用 mongoose 可以使用:Instructor.collection.find({})

观看this video .


下面我写了使用游标批处理数据的解决方案。

在模块的某处添加:

const createCourseForInstructor = (instructor) => {
const data = {
title: faker.lorem.sentence(),
description: faker.lorem.paragraph(),
author: instructor._id,
prise: Math.floor(Math.random()*11), // typo: "prise", must be: "price"
isPublished: 'true',
tags: ["java", "Nodejs", "javascript"]
};
return Course.create(data);
}

const assignCourseToInstructor = (course, instructor) => {
const where = {_id: instructor._id};
const operation = {$push: {courses: course._id}};
return Instructor.collection.updateOne(where, operation, {upsert: false});
}

const processInstructor = async (instructor) => {
let courseIds = [];
for(let i = 0; i < 100; i++) {
try {
const course = await createCourseForInstructor(instructor)
await assignCourseToInstructor(course, instructor);
courseIds.push(course._id);
}
catch (error) {
console.error(error.message);
}
}
console.log(
'Created ', courseIds.length, 'courses for',
'Instructor:', instructor._id,
'Course ids:', courseIds
);
};

并在您的异步 block 中将您的循环替换为:

const cursor = await Instructor.collection.find({}).batchSize(1000);

while(await cursor.hasNext()) {
const instructor = await cursor.next();
await processInstructor(instructor);
}

附言我正在使用 native collection.findcollection.updateOne 来提高性能避免 mongoose 使用extra堆用于模型实例上的 Mongoose 方法和字段。

奖励:

即使如果使用这个游标解决方案,您的代码也会内存不足问题再次运行您的代码,如本例所示(根据服务器的内存以兆字节为单位定义大小):

nodemon --expose-gc --max_old_space_size=10240 app.js

关于JavaScript 堆内存不足 - 插入 mongodb 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53975946/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com