You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB 3.0驱动+Node.js单连接复用查询性能优化方案问询

Great question! Reusing database connections is critical for performance in real-time apps like chat systems—your instinct to fix the repeated connection issue is spot on. Let's walk through how to implement this properly with MongoDB Node.js Driver 3.0+.

Problem Breakdown

Your original db.js creates a new MongoDB connection every time selectData is called. This is a huge performance drain, especially with nested queries, since establishing a database connection is a resource-heavy operation that involves network handshakes and authentication.

Solution: Singleton Connection Pattern

With MongoDB Node.js Driver 3.0+, we can create a single, reusable database connection instance. We'll initialize the connection once, store it, and use it for all subsequent queries. Here's how to implement it:

1. Refactor db.js for Singleton Connection

We'll set up a lazy-loaded connection that only initializes once, then reuse that instance for all database operations. We'll also switch to async/await (supported in 3.0+ drivers) to avoid callback hell and make code cleaner.

const { MongoClient, ObjectId } = require('mongodb');
const settings = require("./settings.js");

// Hold our single database instance
let dbInstance = null;

// Initialize connection (only runs once)
async function getDBConnection() {
  if (dbInstance) {
    // Return existing connection if it's already established
    return dbInstance;
  }
  
  try {
    // Connect to MongoDB with 3.0+ recommended settings
    const client = await MongoClient.connect(settings.db_url, {
      useNewUrlParser: true,
      useUnifiedTopology: true // Required for modern cluster topology handling
    });
    
    dbInstance = client.db(settings.db_name);
    console.log("Successfully connected to MongoDB");
    return dbInstance;
  } catch (err) {
    console.error("Failed to connect to MongoDB:", err);
    throw err; // Let the caller handle connection errors
  }
}

// Reusable database operations
const db = {
  async selectData(collectionName, query = {}, projection = false) {
    const db = await getDBConnection();
    const collection = db.collection(collectionName);
    
    let cursor;
    if (projection) {
      cursor = collection.find(query, { projection });
    } else {
      cursor = collection.find(query);
    }
    
    return cursor.toArray(); // Return a promise instead of using callbacks
  },
  
  // Add other operations (insert, update, delete) using the same connection
  async insertData(collectionName, data) {
    const db = await getDBConnection();
    return db.collection(collectionName).insertOne(data);
  }
};

module.exports = db;

2. Use the Optimized DB in server.js

With the singleton connection, every query—whether single or nested—will reuse the same connection pool. Here's how to use it:

Single Query Example

const db = require("./db.js");

async function fetchTestData() {
  try {
    const data = await db.selectData("testCollection", {});
    console.log("Fetched data:", data);
  } catch (err) {
    console.error("Error fetching data:", err);
  }
}

fetchTestData();

Nested Query Example (No More Repeated Connections)

const db = require("./db.js");

async function runNestedQueries() {
  try {
    // All these queries use the same established connection
    const data1 = await db.selectData("testCollection", {});
    const data2 = await db.selectData("testCollection", {});
    const data3 = await db.selectData("testCollection", {});
    const data4 = await db.selectData("testCollection", {});
    const data5 = await db.selectData("testCollection", {});
    
    console.log("All nested queries completed. Final data:", data5);
  } catch (err) {
    console.error("Error in nested queries:", err);
  }
}

runNestedQueries();

Key Optimizations Explained

  • Singleton Connection: The getDBConnection function checks if a connection already exists before creating a new one, eliminating redundant connection overhead.
  • Async/Await: Replaces callback-based code with cleaner, more maintainable async patterns—perfect for real-time apps where readability and error handling matter.
  • Connection Pooling: MongoDB's Node.js driver uses a connection pool by default (size 5). You can adjust this in the connection options (e.g., poolSize: 10) if you need to handle higher concurrent traffic.
Bonus Tips for Real-Time Apps
  • Handle Connection Drops: Add logic to re-establish the connection if it's lost (listen for client.on('error') events).
  • Clean Up on Shutdown: Close the client connection when your app exits to avoid resource leaks:
    process.on('SIGINT', async () => {
      const client = await MongoClient.connect(settings.db_url);
      await client.close();
      process.exit(0);
    });
    
  • Monitor Connections: Use MongoDB's built-in tools to track connection pool usage and adjust settings as needed.

内容的提问来源于stack exchange,提问作者Vikas Kandari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:12:45