0

0

Mongoose多数据库连接与模型管理深度解析

DDD

DDD

发布时间:2025-07-30 14:42:22

|

470人浏览过

|

来源于php中文网

原创

Mongoose多数据库连接与模型管理深度解析

本教程深入探讨了Mongoose中如何高效管理多个数据库连接。我们将学习如何使用mongoose.createConnection建立独立的数据库连接,以及如何在这些特定连接上正确定义和实例化Mongoose模型,避免常见的TypeError: conn.Price is not a constructor错误,确保数据操作的准确性和隔离性。

Mongoose连接管理:默认与独立连接

在mongoose中,处理数据库连接主要有两种方式:使用mongoose.connect()建立默认连接,以及使用mongoose.createconnection()建立独立的连接实例。

  1. 默认连接 (mongoose.connect()): 当你调用mongoose.connect()时,Mongoose会建立一个全局的、默认的连接。此后,所有直接通过mongoose.model()定义和获取的模型都将绑定到这个默认连接上。这适用于大多数单数据库应用场景。

  2. 独立连接 (mongoose.createConnection()): 对于需要连接到多个数据库、或者需要对不同业务模块使用不同数据库连接的应用,mongoose.createConnection()是理想选择。它会返回一个独立的Connection实例,这个实例拥有自己的连接池和状态,与其他连接互不影响。这意味着你可以为每个数据库创建一个独立的连接对象,并在其上定义和操作模型,从而实现数据库操作的隔离。

    const mongoose = require('mongoose');
    
    // 统一的连接选项,可根据需要调整
    const connectionOptions = {
        useCreateIndex: true,
        useNewUrlParser: true,
        useUnifiedTopology: true,
        useFindAndModify: false
    };
    
    // 建立第一个数据库连接
    const dbEnConnection = mongoose.createConnection("mongodb://localhost/db_en", connectionOptions);
    
    // 建立第二个数据库连接
    const dbFrConnection = mongoose.createConnection("mongodb://localhost/db_fr", connectionOptions);
    
    // 可以在连接成功或失败时进行监听
    dbEnConnection.on('connected', () => console.log('Connected to db_en'));
    dbEnConnection.on('error', (err) => console.error('db_en connection error:', err));
    
    dbFrConnection.on('connected', () => console.log('Connected to db_fr'));
    dbFrConnection.on('error', (err) => console.error('db_fr connection error:', err));

在特定连接上定义和注册模型

当使用mongoose.createConnection()创建了独立的连接实例后,模型的定义和注册方式与默认连接有所不同。你必须在特定的连接实例上调用model()方法来注册模型,而不是在全局的mongoose对象上。

  1. 定义Schema: 首先,像往常一样定义你的Mongoose Schema。Schema是模型的骨架,它定义了文档的结构、数据类型和验证规则。Schema的定义与连接无关,可以在任何地方进行。

    const priceSchema = new mongoose.Schema({
        fixed: {
            1: { type: Number, default: 199 },
            3: { type: Number, default: 499 },
            6: { type: Number, default: 729 },
            12: { type: Number, default: 999 }
        }
    });
    
    const productSchema = new mongoose.Schema({
        name: { type: String, required: true },
        price: { type: Number, required: true },
        currency: { type: String, default: 'USD' }
    });
  2. 在特定连接上注册模型并获取构造函数: 关键在于使用连接实例的model()方法来注册Schema。这个方法接收两个参数:模型名称(字符串)和Schema对象。最重要的是,它会返回一个可以直接用于创建新文档的模型构造函数。

    // 在db_enConnection上注册Price模型
    // PriceModelEn 就是一个构造函数
    const PriceModelEn = dbEnConnection.model('Price', priceSchema);
    
    // 在db_frConnection上注册Product模型
    // ProductModelFr 也是一个构造函数
    const ProductModelFr = dbFrConnection.model('Product', productSchema);

正确实例化和操作模型

一旦你通过connection.model()方法获取了模型构造函数,就可以使用它来创建新的文档实例,并执行保存、查询等操作。

// 使用db_enConnection上的Price模型
async function createPriceDocument() {
    // 正确的实例化方式:使用获取到的模型构造函数
    const priceDoc = new PriceModelEn();

    try {
        await priceDoc.save(); // 使用await确保异步操作完成
        console.log('价格文档已保存到 db_en:', priceDoc);
    } catch (error) {
        console.error('保存价格文档到 db_en 失败:', error);
    }
}

// 使用db_frConnection上的Product模型
async function createProductDocument() {
    // 正确的实例化方式:使用获取到的模型构造函数
    const productDoc = new ProductModelFr({ name: 'French Baguette', price: 2.50 });

    try {
        await productDoc.save();
        console.log('产品文档已保存到 db_fr:', productDoc);
    } catch (error) {
        console.error('保存产品文档到 db_fr 失败:', error);
    }
}

常见错误与最佳实践

错误解析:TypeError: conn.Price is not a constructor

这个错误通常发生在尝试像访问对象属性一样访问模型时,例如new conn.Price()。Mongoose的Connection对象并没有一个名为Price的直接属性来作为模型构造函数。当你调用conn.model('Price', priceSchema)时,它是在该连接实例上注册了一个名为'Price'的模型,并且返回了这个模型的构造函数。因此,你必须捕获这个返回值,并使用它来实例化文档。

区分 mongoose.model() 和 connectionInstance.model()

eSiteGroup站群管理系统1.0.4
eSiteGroup站群管理系统1.0.4

eSiteGroup站群管理系统是基于eFramework低代码开发平台构建,是一款高度灵活、可扩展的智能化站群管理解决方案,全面支持SQL Server、SQLite、MySQL、Oracle等主流数据库,适配企业级高并发、轻量级本地化、云端分布式等多种部署场景。通过可视化建模与模块化设计,系统可实现多站点的快速搭建、跨平台协同管理及数据智能分析,满足政府、企业、教育机构等组织对多站点统一管控的

下载
  • mongoose.model('ModelName', Schema):用于在默认连接上定义和获取模型。
  • connectionInstance.model('ModelName', Schema):用于在特定独立连接上定义和获取模型。

务必根据你使用的连接类型来选择正确的方法。

最佳实践:

  • 明确的变量命名: 将connection.model()返回的模型构造函数赋值给一个清晰的变量名(例如PriceModelEn),这样可以提高代码的可读性,并避免混淆。
  • 异步操作处理: Mongoose的保存和查询操作都是异步的。始终使用async/await或Promise的.then().catch()来处理这些操作,确保代码的正确执行顺序和错误捕获。
  • 连接管理: 在应用程序启动时建立所有必要的连接,并在应用程序关闭时优雅地关闭它们,以释放资源。

完整示例代码

下面是一个整合了上述概念的完整示例,展示了如何使用两个独立的Mongoose连接来操作不同数据库中的模型。

const mongoose = require('mongoose');

// 统一的连接选项
const connectionOptions = {
    useCreateIndex: true,
    useNewUrlParser: true,
    useUnifiedTopology: true,
    useFindAndModify: false
};

// --- 第一数据库连接:db_en ---
const dbEnConnection = mongoose.createConnection("mongodb://localhost/db_en", connectionOptions);

dbEnConnection.on('connected', () => console.log('Successfully connected to db_en'));
dbEnConnection.on('error', (err) => console.error('db_en connection error:', err));
dbEnConnection.on('disconnected', () => console.log('Disconnected from db_en'));

// 定义价格Schema
const priceSchema = new mongoose.Schema({
    fixed: {
        1: { type: Number, default: 199 },
        3: { type: Number, default: 499 },
        6: { type: Number, default: 729 },
        12: { type: Number, default: 999 }
    }
});

// 在db_enConnection上注册Price模型并获取构造函数
const PriceModelEn = dbEnConnection.model('Price', priceSchema);

// --- 第二数据库连接:db_fr ---
const dbFrConnection = mongoose.createConnection("mongodb://localhost/db_fr", connectionOptions);

dbFrConnection.on('connected', () => console.log('Successfully connected to db_fr'));
dbFrConnection.on('error', (err) => console.error('db_fr connection error:', err));
dbFrConnection.on('disconnected', () => console.log('Disconnected from db_fr'));

// 定义产品Schema
const productSchema = new mongoose.Schema({
    name: { type: String, required: true },
    price: { type: Number, required: true },
    currency: { type: String, default: 'EUR' }
});

// 在db_frConnection上注册Product模型并获取构造函数
const ProductModelFr = dbFrConnection.model('Product', productSchema);

// --- 示例操作函数 ---

async function createPriceDocument() {
    console.log('\n--- 尝试在 db_en 中创建价格文档 ---');
    const priceDoc = new PriceModelEn(); // 使用正确的模型构造函数
    try {
        await priceDoc.save();
        console.log('价格文档已成功保存到 db_en:', priceDoc);
    } catch (error) {
        console.error('保存价格文档到 db_en 失败:', error.message);
    }
}

async function createProductDocument() {
    console.log('\n--- 尝试在 db_fr 中创建产品文档 ---');
    const productDoc = new ProductModelFr({ name: 'Laptop', price: 1200.00 });
    try {
        await productDoc.save();
        console.log('产品文档已成功保存到 db_fr:', productDoc);
    } catch (error) {
        console.error('保存产品文档到 db_fr 失败:', error.message);
    }
}

async function runAllExamples() {
    await createPriceDocument();
    await createProductDocument();

    // 示例查询
    console.log('\n--- 尝试从 db_en 查询价格文档 ---');
    try {
        const prices = await PriceModelEn.find({});
        console.log('db_en 中的价格文档:', prices);
    } catch (error) {
        console.error('从 db_en 查询失败:', error.message);
    }

    console.log('\n--- 尝试从 db_fr 查询产品文档 ---');
    try {
        const products = await ProductModelFr.find({});
        console.log('db_fr 中的产品文档:', products);
    } catch (error) {
        console.error('从 db_fr 查询失败:', error.message);
    }

    // 关闭所有连接
    console.log('\n--- 关闭数据库连接 ---');
    await dbEnConnection.close();
    await dbFrConnection.close();
    console.log('所有数据库连接已关闭。');
}

// 运行所有示例
runAllExamples().catch(console.error);

总结

通过本教程,我们深入理解了Mongoose中多数据库连接的管理策略。核心要点在于:当使用mongoose.createConnection()建立独立连接时,必须在该连接实例上调用connection.model()来注册和获取模型构造函数。避免直接将连接对象作为模型的容器(如conn.Price),因为这会导致TypeError。正确地使用connection.model()的返回值,将使你在Mongoose多数据库环境中高效、准确地进行数据操作。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

309

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

222

2025.10.31

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

298

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

212

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1502

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

624

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

633

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

589

2024.04.29

java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

1

2026.01.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MongoDB 教程
MongoDB 教程

共17课时 | 2.4万人学习

黑马云课堂mongodb实操视频教程
黑马云课堂mongodb实操视频教程

共11课时 | 3.1万人学习

MongoDB 教程
MongoDB 教程

共42课时 | 27.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号