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

标签 javascript node.js mongodb express mongodb-query

我想在 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/

相关文章:

javascript - Meteor 在刷新后显示额外的结果,即使数据库只有单行

mongodb - MongoDB whole/data/db在一次电击导致crash后没了正常吗

node.js - Mongoose:过滤查询结果

javascript - 背景三 Angular 形代替圆形JS

javascript - 在 JavaScript 中无限打印到控制台整数之间的值

mysql - 为现有 MySQL 数据库定义 Sequelize 模型

javascript - 让 webfontloader 与 node.js 和 jsdom 一起工作

javascript - 确认谷歌分析是否得到很好的实现

javascript - JavaScript 中的 JSON pretty-print

node.js - 如何修复 "Response to preflight request doesn' t 通过访问控制检查 : It does not have HTTP ok status"error in react app with nodejs api