MST

星途 面试题库

面试题:Node.js 文件系统与 MongoDB 高并发交互优化

在 Node.js 项目中,有大量小文件需要读取,每个文件包含一段 JSON 数据,需要将这些 JSON 数据解析后插入到 MongoDB 数据库的 documents 集合中。由于文件数量多,并发处理时可能出现性能问题。请描述你会采用哪些策略和技术手段来优化文件读取与数据库插入的性能,并给出核心代码示例。
48.0万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

策略和技术手段

  1. 文件读取优化
    • 流处理:使用 Node.js 的 fs.createReadStream 以流的方式读取文件,避免一次性将整个文件读入内存,减少内存占用。
    • 队列处理:为避免过多并发导致性能问题,可以使用队列来控制文件读取的并发数量,例如 async 库的 queue
  2. 数据库插入优化
    • 批量插入:使用 MongoDB 的 insertMany 方法代替单个插入,减少数据库交互次数。
    • 连接池:使用 mongoose 或原生 MongoDB 驱动时,合理配置连接池,复用数据库连接,减少连接建立和销毁的开销。

核心代码示例

const fs = require('fs');
const path = require('path');
const { MongoClient } = require('mongodb');
const async = require('async');

// 数据库连接配置
const uri = "mongodb://localhost:27017";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true });
const dbName = "yourDatabaseName";
const collectionName = "documents";

// 读取文件目录
const directoryPath = path.join(__dirname, 'yourFilesDirectory');

async function main() {
    try {
        // 连接数据库
        await client.connect();
        console.log('Connected to MongoDB');

        const db = client.db(dbName);
        const collection = db.collection(collectionName);

        // 读取目录下所有文件
        const files = fs.readdirSync(directoryPath);

        // 使用队列控制并发读取文件
        const q = async.queue(async (file, callback) => {
            const filePath = path.join(directoryPath, file);
            const data = await new Promise((resolve, reject) => {
                let fileData = '';
                const readStream = fs.createReadStream(filePath, { encoding: 'utf8' });
                readStream.on('data', (chunk) => {
                    fileData += chunk;
                });
                readStream.on('end', () => {
                    resolve(fileData);
                });
                readStream.on('error', (err) => {
                    reject(err);
                });
            });
            const jsonData = JSON.parse(data);
            callback(null, jsonData);
        }, 5); // 并发数设为5

        const allData = [];
        q.drain(() => {
            // 批量插入数据到 MongoDB
            collection.insertMany(allData)
              .then(() => {
                    console.log('Data inserted successfully');
                })
              .catch((err) => {
                    console.error('Error inserting data:', err);
                })
              .finally(() => {
                    client.close();
                });
        });

        files.forEach((file) => {
            q.push(file, (err, result) => {
                if (!err) {
                    allData.push(result);
                }
            });
        });

    } catch (e) {
        console.error(e);
    }
}

main();