
本教程深入探讨了Mongoose中如何高效管理多个数据库连接。我们将学习如何使用mongoose.createConnection建立独立的数据库连接,以及如何在这些特定连接上正确定义和实例化Mongoose模型,避免常见的TypeError: conn.Price is not a constructor错误,确保数据操作的准确性和隔离性。
Mongoose连接管理:默认与独立连接
在mongoose中,处理数据库连接主要有两种方式:使用mongoose.connect()建立默认连接,以及使用mongoose.createconnection()建立独立的连接实例。
默认连接 (mongoose.connect()):当你调用mongoose.connect()时,Mongoose会建立一个全局的、默认的连接。此后,所有直接通过mongoose.model()定义和获取的模型都将绑定到这个默认连接上。这适用于大多数单数据库应用场景。
独立连接 (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对象上。
定义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' }});
在特定连接上注册模型并获取构造函数:关键在于使用连接实例的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()
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'));// 定义价格Schemaconst 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'));// 定义产品Schemaconst 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多数据库环境中高效、准确地进行数据操作。
以上就是Mongoose多数据库连接与模型管理深度解析的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1512723.html
微信扫一扫
支付宝扫一扫