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+.
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.
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
getDBConnectionfunction 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.
- 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

