Join us Sept 17 at .local NYC! Use code WEB50 to save 50% on tickets. Learn more >
MongoDB Event
Docs 菜单
Docs 主页
/ / /
Node.js 驱动程序
/

教程:单个应用程序中的多个MongoDB连接

大多数应用程序使用单个MongoDB连接。但是,某些应用程序可从多个连接中受益,从而实现数据分离、性能优化或架构要求。

在本教程中,您将学习;了解如何在单个 Node.js应用程序中建立多个MongoDB连接。

多个MongoDB连接对于需要数据分离、提高性能或架构灵活性的应用程序非常有用。

多个MongoDB连接的常见用例包括:

  • 多租户应用程序:每个租户使用具有自己连接的单独数据库,以实现数据隔离性和安全性

  • 微服务架构:每个服务都维护自己的专用数据库连接

  • 负载分布:将写入操作分布到多个数据库实例

  • 数据处理:同时从多个MongoDB服务器检索数据以进行分析或报告

考虑一个多租户应用程序,其中不同的租户或客户股票相同的 Web应用程序,但需要单独、隔离的数据库。在这种情况下,每个租户都可以拥有自己专用的MongoDB连接。这确保了每个租户的数据分离、安全性和自定义性,同时所有租户都在同一应用程序中运行。这种方法简化了管理,并提供了一种在新租户加入平台时进行扩展的方法,而不影响现有租户。

在探索如何在应用程序中实现多个连接时,请考虑以下MongoDB概念:

  • 负载均衡

  • 分片

  • 读取副本

  • 容错

这些概念在需要多个MongoDB连接以实现高效数据管理和性能优化的场景中发挥角色。

在本教程中,您将执行以下操作:

  • 设置环境并安装所需的依赖项

  • 连接至 MongoDB

  • 设置主节点 (primary node in the replica set)MongoDB连接

  • 设置从节点(secondary node from replica set)MongoDB连接

  • 使用现有模式

  • 设置模式灵活性

  • 在同一连接中切换数据库

在开始本教程之前,您必须有一个MongoDB Atlas 群集。要学习;了解如何创建免费的MongoDB Atlas 群集,请参阅Atlas入门教程

注意

本教程使用MongoDB Server 8.0.12 和 Node.js 版本 20.15.1。

1

为项目创建一个新目录并初始化一个新的 Node.js项目:

mkdir mongodb-multiple-connections
cd mongodb-multiple-connections
npm init -y
2

安装本教程所需的依赖项:

npm install express mongoose

本教程使用Express.js 作为 Web框架,使用Mongoose进行MongoDB对象建模。

注意

本教程使用Mongoose,这是一个流行的MongoDB对象数据建模 (ODM) 库。有关Mongoose入门的更多信息,请参阅 Mongoose入门教程

3

在项目根目录中创建 .env文件来存储MongoDB连接字符串:

touch .env

将以下环境变量添加到 .env文件中:

PRIMARY_CONN_STR=<your-primary-connection-string>
SECONDARY_CONN_STR=<your-secondary-connection-string>

将占位符值替换为实际的MongoDB Atlas连接字符串。要学习;了解如何查找MongoDB Atlas连接字符串,请参阅连接到集群教程。

安装 dotenv包以加载环境变量:

npm install dotenv

您现在已经有了一个项目,可以在应用程序中设立多个MongoDB连接。

完成本教程后,此应用程序的项目目录将具有以下结构:

mongodb-multiple-connections/
├── .env # Environment variables
├── package.json # Project dependencies
├── package-lock.json # Dependency lock file
├── node_modules/ # Installed packages
├── index.js # Main application file
├── db.primary.js # Primary connection configuration
├── db.secondary.js # Secondary connection configuration
└── product.schema.js # Product schema definition

您将在本教程中创建的密钥文件提供服务以下用途:

  • 索引.js :导入和使用这两个连接的主应用程序文件

  • db.主节点 (primary node in the replica set).js :使用 mongoose.connect() 配置主节点 (primary node in the replica set)MongoDB连接

  • db.从节点(secondary node from replica set).js :使用 mongoose.createConnection() 配置从节点(secondary node from replica set)MongoDB连接

  • 产品。模式.js:为两个连接定义可重用产品模式

  • .env:安全地存储MongoDB连接字符串

在本节中,学习;了解如何使用Mongoose在应用程序中设立主节点 (primary node in the replica set)MongoDB连接。使用 mongoose.connect()方法为主应用程序建立主节点 (primary node in the replica set)MongoDB 数据库连接。此方法为整个应用程序管理单个连接池。

1

在名为 db.primary.js 的新文件中,定义要在主应用程序文件index.js 中使用的连接方法。此方法可配置MongoDB连接并处理事件。将以下代码复制并粘贴到 db.primary.js文件中:

require('dotenv').config();
const mongoose = require("mongoose");
module.exports = async (uri, options = {}) => {
// By default, Mongoose skips properties not defined in the schema (strictQuery).
// You can adjust it based on your configuration.
mongoose.set('strictQuery', true);
// Connect to MongoDB
try {
await mongoose.connect(uri, options);
console.info("MongoDB primary connection initiated");
} catch (err) {
console.error("MongoDB primary connection failed, " + err);
}
// Event handling
mongoose.connection.once('open', () => console.info("MongoDB primary connection opened!"));
mongoose.connection.on('connected', () => console.info("MongoDB primary connection succeeded!"));
mongoose.connection.on('error', (err) => {
console.error("MongoDB primary connection failed, " + err);
mongoose.disconnect();
});
mongoose.connection.on('disconnected', () => console.info("MongoDB primary connection disconnected!"));
// Graceful exit
process.on('SIGINT', async () => {
try {
await mongoose.connection.close();
console.info("Mongoose primary connection disconnected through app termination!");
process.exit(0);
} catch (err) {
console.error("Error during graceful shutdown:", err);
process.exit(1);
}
});
}
2

创建用于在应用程序中执行操作的模式。在名为 product.schema.js 的单独文件中写入模式并将其导出,如以下代码所示:

const mongoose = require("mongoose");
module.exports = (options = {}) => {
// Schema for Product
return new mongoose.Schema(
{
store: {
_id: mongoose.Types.ObjectId, // Reference-id to the store collection
name: String
},
name: String,
price: Number,
category: String,
description: String
// add required properties
},
options
);
}
3

在主 index.js文件中导入 db.primary.js文件,并使用其中定义的方法建立主节点 (primary node in the replica set)MongoDB连接。如果需要,还可以传递可选的连接选项对象。

然后,导入 product.schema.js文件以访问权限产品模式。这使您可以创建模型并执行与应用程序中的产品相关的操作。将以下代码复制并粘贴到 index.js文件中,以设立主节点 (primary node in the replica set)连接并对示例产品数据执行操作:

// Load environment variables
require('dotenv').config();
const mongoose = require("mongoose");
// Async function to establish the primary MongoDB connection
async function establishPrimaryConnection() {
try {
await require("./db.primary.js")(process.env.PRIMARY_CONN_STR, {
// (optional) connection options
});
} catch (error) {
console.error('Failed to establish primary connection:', error);
process.exit(1);
}
}
// Initialize connection
establishPrimaryConnection();
// Import Product Schema
const productSchema = require("./product.schema.js")({
collection: "products",
// Pass configuration options if needed
});
// Create Model
const ProductModel = mongoose.model("Product", productSchema);
// Sample products data
const sampleProducts = [
{
name: "Laptop Pro",
price: 1299.99,
category: "Electronics",
description: "High-performance laptop for professionals"
},
{
name: "Wireless Headphones",
price: 199.99,
category: "Electronics",
description: "Premium noise-cancelling headphones"
},
{
name: "Coffee Maker",
price: 89.99,
category: "Kitchen",
description: "Automatic drip coffee maker"
}
];
// Wait for connection to be ready before executing operations
mongoose.connection.once('open', async () => {
console.log('Primary database connected, executing operations...');
try {
// Check if products already exist
const existingCount = await ProductModel.countDocuments();
console.log(`Existing products in primary DB: ${existingCount}`);
if (existingCount === 0) {
console.log('Inserting sample products into primary database...');
await ProductModel.insertMany(sampleProducts);
console.log('Sample products inserted into primary database!');
}
// Find and display a product
let product = await ProductModel.findOne();
console.log('Product found in primary DB:', product);
// Display all products
const allProducts = await ProductModel.find();
console.log(`Total products in primary DB: ${allProducts.length}`);
} catch (error) {
console.error('Error with primary database operations:', error);
}
});
Primary database connected, executing operations...
MongoDB primary connection initiated
Existing products in primary DB: 3
Product found in primary DB: {
_id: new ObjectId('...'),
name: 'Laptop Pro',
__v: 0
}
Total products in primary DB: 3

您的应用程序需要多个MongoDB连接。

您可以为各种使用案例配置从节点(secondary node from replica set)MongoDB连接。在本节中,学习;了解如何设立和使用从节点(secondary node from replica set)连接。

1

使用 mongoose.createConnection() 在 文件中创建连接代码db.secondary.js方法。此方法允许您建立单独的连接池,每个连接池都根据特定使用案例或数据访问模式定制,这与您之前用于主节点 (primary node in the replica set)MongoDB连接的 mongoose.connect() 方法不同:

const mongoose = require("mongoose");
module.exports = (uri, options = {}) => {
// Connect to MongoDB
const db = mongoose.createConnection(uri, options);
// By default, Mongoose skips properties not defined in the schema (strictQuery).
// Adjust it based on your configuration.
db.set('strictQuery', true);
// Event handling
db.once('open', () => console.info("MongoDB secondary connection opened!"));
db.on('connected', () => console.info(`MongoDB secondary connection succeeded!`));
db.on('error', (err) => {
console.error(`MongoDB secondary connection failed, ` + err);
db.close();
});
db.on('disconnected', () => console.info(`MongoDB secondary connection disconnected!`));
// Graceful exit
process.on('SIGINT', async () => {
try {
await db.close();
console.info(`Mongoose secondary connection disconnected through app termination!`);
process.exit(0);
} catch (err) {
console.error("Error during graceful shutdown:", err);
process.exit(1);
}
});
// Export db object
return db;
}
2

在主 index.js文件中导入 db.secondary.js文件,使用名为 db 的变量创建连接对象,并使用其中定义的方法建立从节点(secondary node from replica set)MongoDB连接。如果需要,还可以传递可选的连接选项对象。将以下代码添加到 index.js文件的末尾:

// Load environment variables
require('dotenv').config();
// Establish the secondary MongoDB connection
const db = require("./db.secondary.js")(process.env.SECONDARY_CONN_STR, {
// (optional) connection options
});
// Import Product Schema
const SecondaryProductSchema = require("./product.schema.js")({
collection: "products",
// Pass configuration options if needed
});
// Create Model using the secondary connection
const SecondaryProductModel = db.model("Product", SecondaryProductSchema);
// Sample products data for secondary database
const SecondarySampleProducts = [
{
name: "Smart Watch",
price: 199.99,
category: "Electronics",
description: "Advanced fitness tracking smartwatch"
},
{
name: "Bluetooth Speaker",
price: 79.99,
category: "Electronics",
description: "Portable wireless speaker with premium sound"
},
{
name: "Desk Lamp",
price: 49.99,
category: "Home",
description: "LED desk lamp with adjustable brightness"
}
];
// Wait for secondary connection to be ready before executing operations
db.once('open', async () => {
console.log('Secondary database connected, executing operations...');
try {
// Check if products already exist
const existingCount = await SecondaryProductModel.countDocuments();
console.log(`Existing products in secondary DB: ${existingCount}`);
if (existingCount === 0) {
console.log('Inserting sample products into secondary database...');
await SecondaryProductModel.insertMany(SecondarySampleProducts);
console.log('Sample products inserted into secondary database!');
}
// Find and display a product
let product = await SecondaryProductModel.findOne();
console.log('Product found in secondary DB:', product);
// Display all products
const allProducts = await SecondaryProductModel.find();
console.log(`Total products in secondary DB: ${allProducts.length}`);
} catch (error) {
console.error('Error with secondary database operations:', error);
}
});
Primary database connected, executing operations...
MongoDB primary connection initiated
MongoDB secondary connection succeeded!
MongoDB secondary connection opened!
Secondary database connected, executing operations...
Existing products in primary DB: 3
Existing products in secondary DB: 6
Product found in primary DB: {
_id: new ObjectId('...'),
name: 'Laptop Pro',
__v: 0
}
Product found in secondary DB: {
_id: new ObjectId('...'),
name: 'Smart Watch',
__v: 0
}
Total products in primary DB: 3
Total products in secondary DB: 3

现在,您已经设立了连接,可以使用新的 db对象来创建模型。以下部分探讨了不同的场景和示例,以帮助您选择最适合您的特定数据访问和管理需求的设置。

如果两个连接在同一数据模型上运行,请使用在主节点 (primary node in the replica set)连接中使用的相同 product.schema.js文件。

导入 product.schema.js文件以访问权限产品模式。这样,您就可以使用 db对象创建模型,并执行与应用程序中的产品相关的操作:

// Import Product Schema
const secondaryProductSchema = require("./product.schema.js")({
collection: "products",
// Pass configuration options if needed
});
// Create Model
const SecondaryProductModel = db.model("Product", secondaryProductSchema);
// Wait for secondary connection to be ready before executing operations
db.once('open', async () => {
console.log('Secondary database connected, executing operations...');
try {
// Check if products already exist in secondary database
const existingCount = await SecondaryProductModel.countDocuments();
console.log(`Existing products in secondary DB: ${existingCount}`);
if (existingCount === 0) {
console.log('Inserting sample products into secondary database...');
await SecondaryProductModel.insertMany(sampleProducts);
console.log('Sample products inserted into secondary database!');
}
// Find and display a product
let product = await SecondaryProductModel.findOne();
console.log('Product found in secondary DB:', product);
// Display all products
const allProducts = await SecondaryProductModel.find();
console.log(`Total products in secondary DB: ${allProducts.length}`);
} catch (error) {
console.error('Error with secondary database operations:', error);
}
});

要查看在项目中使用主节点 (primary node in the replica set)数据库连接到从从节点(secondary node from replica set)MongoDB连接的现有模式的实际代码示例和可用资源,请访问使用现有模式Github存储库。

使用多个MongoDB连接时,必须根据特定使用案例灵活地调整模式。尽管主节点 (primary node in the replica set)连接可能需要带有验证的严格模式以确保数据完整性,但在某些情况下,从节点(secondary node from replica set)连接有不同的用途。实例,从节点(secondary node from replica set)连接可能会在存档服务器上存储用于分析的数据,并具有由过去使用案例驱动的不同模式要求。在本节中,您将了解如何为从从节点(secondary node from replica set)连接配置模式灵活性,从而满足应用程序的独特需求。

如果您希望在Mongoose中获得模式灵活性,请在为从从节点(secondary node from replica set)连接配置模式时在模式选项中传递 strict: false属性。这允许您处理不严格遵循模式的数据。

导入 product.schema.js文件以访问权限产品模式。这样,您就可以使用 db对象创建模型,并执行与应用程序中的产品相关的操作:

// Import Product Schema
const secondaryProductSchema = require("./product.schema.js")({
collection: "products",
strict: false
// Pass configuration options if needed
});
// Create Model
const SecondaryProductModel = db.model("Product", secondaryProductSchema);
// Wait for secondary connection to be ready before executing operations
db.once('open', async () => {
console.log('Secondary database (flexible schema) connected, executing operations...');
try {
// Check if products already exist in secondary database
const existingCount = await SecondaryProductModel.countDocuments();
console.log(`Existing products in secondary DB: ${existingCount}`);
if (existingCount === 0) {
// Add extra fields to demonstrate schema flexibility
const flexibleSampleProducts = sampleProducts.map(product => ({
...product,
extraField: "This field is not in the schema but will be saved due to strict: false",
timestamp: new Date()
}));
console.log('Inserting sample products with extra fields into secondary database...');
await SecondaryProductModel.insertMany(flexibleSampleProducts);
console.log('Sample products with extra fields inserted into secondary database!');
}
// Find and display a product
let product = await SecondaryProductModel.findOne();
console.log('Product found in secondary DB (flexible schema):', product);
// Display all products
const allProducts = await SecondaryProductModel.find();
console.log(`Total products in secondary DB: ${allProducts.length}`);
} catch (error) {
console.error('Error with secondary database operations:', error);
}
});

要查看在项目的从节点(secondary node from replica set)MongoDB连接中设置模式灵活性的实际代码示例和可用资源,请参阅设置模式灵活性Github存储库。

在应用程序的数据库设置中,您可以使用db.useDb()方法在不同数据库之间切换。此方法允许您创建与特定数据库关联的新连接对象,同时共享同一连接池。

这种方法允许您使用单个连接管理应用程序中的多个数据库,同时为每个数据库维护不同的数据上下文。

导入 product.schema.js文件以访问权限产品模式。这样,您就可以使用 db对象创建模型,并执行与应用程序中的产品相关的操作。

考虑一个电子商务平台,其中多个商店独立运营,每个存储维护自己的产品管理数据库。使用 db.useDb() 方法在不同存储数据库之间切换,同时保持共享连接池,如以下示例所示:

// Load environment variables
require('dotenv').config();
// Establish the secondary MongoDB connection
const db = require("./db.secondary.js")(process.env.SECONDARY_CONN_STR, {
// (optional) connection options
});
// Import Product Schema
const secondaryProductSchema = require("./product.schema.js")({
collection: "products",
// strict: false // that doesn't adhere strictly to the schema!
// Pass configuration options if needed
});
// Base sample products data
const sampleProducts = [
{
name: "Laptop Pro",
price: 1299.99,
category: "Electronics",
description: "High-performance laptop for professionals"
},
{
name: "Wireless Headphones",
price: 199.99,
category: "Electronics",
description: "Premium noise-cancelling headphones"
},
{
name: "Coffee Maker",
price: 89.99,
category: "Kitchen",
description: "Automatic drip coffee maker"
}
];
// Sample store-specific products
const storeAProducts = sampleProducts.map(product => ({
...product,
store: { name: "Store A" },
storeId: "A"
}));
const storeBProducts = [
{
name: "Gaming Chair",
price: 299.99,
category: "Furniture",
description: "Ergonomic gaming chair with RGB lighting",
store: { name: "Store B" },
storeId: "B"
},
{
name: "Mechanical Keyboard",
price: 149.99,
category: "Electronics",
description: "RGB mechanical gaming keyboard",
store: { name: "Store B" },
storeId: "B"
}
];
// Create a connection for 'Store A'
const storeA = db.useDb('StoreA');
// Create Model
const SecondaryStoreAProductModel = storeA.model("Product", secondaryProductSchema);
// Wait for Store A connection to be ready
storeA.once('open', async () => {
console.log('Store A database connected, executing operations...');
try {
// Check if products already exist in Store A
const existingCount = await SecondaryStoreAProductModel.countDocuments();
console.log(`Existing products in Store A: ${existingCount}`);
if (existingCount === 0) {
console.log('Inserting sample products into Store A database...');
await SecondaryStoreAProductModel.insertMany(storeAProducts);
console.log('Sample products inserted into Store A database!');
}
// Find and display a product
let product = await SecondaryStoreAProductModel.findOne();
console.log('Product found in Store A:', product);
// Display all products
const allProducts = await SecondaryStoreAProductModel.find();
console.log(`Total products in Store A: ${allProducts.length}`);
} catch (error) {
console.error('Error with Store A operations:', error);
}
});
// Create a connection for 'Store B'
const storeB = db.useDb('StoreB');
// Create Model
const SecondaryStoreBProductModel = storeB.model("Product", secondaryProductSchema);
// Wait for Store B connection to be ready
storeB.once('open', async () => {
console.log('Store B database connected, executing operations...');
try {
// Check if products already exist in Store B
const existingCount = await SecondaryStoreBProductModel.countDocuments();
console.log(`Existing products in Store B: ${existingCount}`);
if (existingCount === 0) {
console.log('Inserting sample products into Store B database...');
await SecondaryStoreBProductModel.insertMany(storeBProducts);
console.log('Sample products inserted into Store B database!');
}
// Find and display a product
let product = await SecondaryStoreBProductModel.findOne();
console.log('Product found in Store B:', product);
// Display all products
const allProducts = await SecondaryStoreBProductModel.find();
console.log(`Total products in Store B: ${allProducts.length}`);
} catch (error) {
console.error('Error with Store B operations:', error);
}
});

前面的示例为 Store AStore B 建立了单独的数据库连接,每个存储都包含自己的产品数据。这种方法提供了数据分离,同时利用单个共享连接池进行高效的资源管理。

前面的静态方法使用预定义名称(StoreAStoreB)为每个存储创建显式连接。

对于动态存储管理,创建一个函数,接受存储标识符作为参数并返回连接对象。此功能支持按标识符进行存储切换,并重用现有连接以提高效率。

// Function to get connection object for particular store's database
function getStoreConnection(storeId) {
return db.useDb("Store"+storeId, { useCache: true });
}
// Create a connection for 'Store A'
const store = getStoreConnection("A");
// Create Model
const SecondaryStoreProductModel = store.model("Product", secondaryProductSchema);
// Wait for store connection to be ready
store.once('open', async () => {
console.log('Store A (dynamic) database connected, executing operations...');
try {
// Check if products already exist in the store
const existingCount = await SecondaryStoreProductModel.countDocuments();
console.log(`Existing products in Store A (dynamic): ${existingCount}`);
if (existingCount === 0) {
// Use the same store A products from the previous example
console.log('Inserting sample products into Store A (dynamic) database...');
await SecondaryStoreProductModel.insertMany(storeAProducts);
console.log('Sample products inserted into Store A (dynamic) database!');
}
// Find and display a product
let product = await SecondaryStoreProductModel.findOne();
console.log('Product found in Store A (dynamic):', product);
// Display all products
const allProducts = await SecondaryStoreProductModel.find();
console.log(`Total products in Store A (dynamic): ${allProducts.length}`);
} catch (error) {
console.error('Error with Store A (dynamic) operations:', error);
}
});

在动态方法中,根据需要创建和缓存连接实例,从而无需手动管理每个存储的单独连接。对于需要在应用程序中处理多个商店的情况,这种方法可提高灵活性和资源效率。

要查看将同一连接中的数据库切换到项目中从节点(secondary node from replica set)MongoDB连接的实际代码示例和可用资源,请访问Github存储库。

本教程演示如何使用Mongoose在 Node.js应用程序中实现多个MongoDB连接。您学习了如何建立主节点 (primary node in the replica set)和从节点(secondary node from replica set)连接、实现模式灵活性以及管理单个连接池的多个数据库。

这些技术启用数据分离、提高性能和架构灵活性。现在,您可以实现满足特定应用程序要求的连接策略。当您继续使用多个MongoDB连接时,请考虑以下最佳实践和其他资源。

在 Node.js应用程序中实现多个MongoDB连接时,请遵循以下最佳实践:

  • 连接池化:使用连接池化有效管理MongoDB连接。连接池化支持连接重用并减少开销。要学习;了解更多信息,请参阅服务器手册中的连接池和MongoDB Node.js驾驶员文档中的使用连接池管理连接

  • 错误处理:实施适当的错误处理、日志记录和恢复机制,确保连接可靠性。

  • 安全性:处理敏感数据时实施身份验证、授权和安全通信实践。有关更多信息,请参阅保护您的数据。

  • 可扩展性:设计连接策略以支持水平和垂直扩展要求。

  • 测试:在各种条件下测试多连接设置,包括故障转移场景、高负载和资源限制。

要学习;了解有关Mongoose入门的更多信息,请参阅第三方集成部分中的Mongoose入门教程。

要学习;了解有关将Mongoose与MongoDB结合使用的更多信息,请参阅Mongoose文档。

要学习;了解有关在 Node.js应用程序中完整实施多个MongoDB连接的更多信息,请参阅Github存储库。

后退

连接故障排除

在此页面上