单节点项目中的猫鼬和多个数据库


122

我正在做一个包含子项目的Node.js项目。一个子项目将拥有一个Mongodb数据库,Mongoose将用于包装和查询db。但是问题是

  • 猫鼬不允许在一个猫鼬实例中使用多个数据库,因为模型建立在一个连接上。
  • 要使用多个猫鼬实例,Node.js不允许使用多个模块实例,因为它在中具有缓存系统require()。我知道在Node.js中禁用模块缓存,但是我认为这不是一个好的解决方案,因为它只需要猫鼬。

    我尝试使用createConnection()openSet()猫鼬,但这不是解决方案。

    我试图深度复制猫鼬实例(http://blog.imaginea.com/deep-copy-in-javascript/),以将新的猫鼬实例传递给子项目,但是它抛出RangeError: Maximum call stack size exceeded

我想知道是否存在将多个数据库与猫鼬一起使用或解决此问题的任何解决方法?因为我认为猫鼬非常容易和快速。还是任何其他模块作为建议?

Answers:


37

您可以做的一件事是,每个项目可能都有子文件夹。因此,在该子文件夹中安装mongoose并从每个子应用程序中自己的文件夹中进行require()猫鼬。并非来自项目根目录或全局。因此,一个子项目,一个猫鼬安装和一个猫鼬实例。

-app_root/
--foo_app/
---db_access.js
---foo_db_connect.js
---node_modules/
----mongoose/
--bar_app/
---db_access.js
---bar_db_connect.js
---node_modules/
----mongoose/

在foo_db_connect.js中

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/foo_db');
module.exports = exports = mongoose;

在bar_db_connect.js中

var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/bar_db');
module.exports = exports = mongoose;

在db_access.js文件中

var mongoose = require("./foo_db_connect.js"); // bar_db_connect.js for bar app

现在,您可以使用猫鼬访问多个数据库。


2
这意味着每个项目都会有自己的连接。您将无法管理10万个连接。我认为最好使用useDb使用相同连接池的命令。
xpepermint 2015年

1
xpepermint你能够显示useDb一个例子-我有这个问题目前stackoverflow.com/questions/37583198/...
Lion789

4
这似乎给项目带来了沉重负担。你不是这样吗
Eshwar Prasad Yaddanapudi

1
每个应用程序具有几个不同的连接实例(例如,用于用户数据库,会话数据库以及用于应用程序数据)绝对可以。它不是“巨大的负担”,也不是引起扩展问题的常见情况。
伊恩·柯林斯

你是我最好的朋友!非常感谢!这个对我有用!谢谢!
Biruel Rick

214

根据高级手册createConnection() 用于连接到多个数据库。

但是,您需要为每个连接/数据库创建单独的模型:

var conn      = mongoose.createConnection('mongodb://localhost/testA');
var conn2     = mongoose.createConnection('mongodb://localhost/testB');

// stored in 'testA' database
var ModelA    = conn.model('Model', new mongoose.Schema({
  title : { type : String, default : 'model in testA database' }
}));

// stored in 'testB' database
var ModelB    = conn2.model('Model', new mongoose.Schema({
  title : { type : String, default : 'model in testB database' }
}));

我很确定您可以在它们之间共享架构,但是您必须检查以确保。


4
是的,我认为命名连接和共享模式是解决之道。根据Robert的示例,每个连接都需要一个唯一的模型。
西蒙·霍尔姆斯

21
useDb()可以在3.8中进行检出以共享基础连接池:github.com/LearnBoost/mongoose/wiki/…–
aaronheckmann

1
假设我有自动生成的数据库(说n个数据库)。没有一两个。有什么方法可以连接到这些数据库而无需为每个数据库创建单独的模型?
Anooj Krishnan G

1
@AnoojKrishnanG我认为不可能,不。您需要针对每个数据库分别创建模型。但是,正如我在回答中已经指出的那样,您也许可以在连接之间共享架构,这可以节省一些编码时间。
robertklep 2015年

1
您可以在不同的模型之间共享模式,因此可以在数据库之间共享。var newSchema = new mongoose.Schema({ ... })var model2 = conn1.model('newModel', newSchema)var model2 = conn2.model('newModel', newSchema)
授予

41

太晚了,但这可能会对某人有所帮助。当前答案假定您为连接和模型使用相同的文件。

在现实生活中,很有可能将模型拆分为不同的文件。您可以在主文件中使用以下内容:

mongoose.connect('mongodb://localhost/default');

const db = mongoose.connection;

db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
  console.log('connected');
});

这就是文档中描述的方式。然后在模型文件中,执行以下操作:

import mongoose, { Schema } from 'mongoose';

const userInfoSchema = new Schema({
  createdAt: {
    type: Date,
    required: true,
    default: new Date(),
  },
  // ...other fields
});

const myDB = mongoose.connection.useDb('myDB');

const UserInfo = myDB.model('userInfo', userInfoSchema);

export default UserInfo;

其中myDB是您的数据库名称。


谢谢-我能够在单个应用程序中使用以下三个数据库:const mongoose = require('mongoose'); const Schema = mongoose.Schema; const mySchema =新模式({}); const mydbvar = mongoose.connection.useDb('mydb')module.exports = mydbvar.model('myCollection',MySchema);
Johnathan Enslin,

2
绝对是最好,最真实的例子。连接到默认数据库(就像使用SQL Server一样),然后利用useDb将DML定位到适当的数据库。(这有助于将用户保留在一个数据库中,而将数据保留在另一个数据库中。)最终将请求发送到同一服务器时,无需开始建立多个连接。现在,如果您要连接到两个不同的服务器,那就不一样了。
Newclique

2
正如@Wade所说,据我了解,该解决方案仅在所有数据库都在同一服务器上时才有效。目前尚不清楚这是否回答了OP的问题,并且IMO有点误导。
joniba '19

这正是我从进行MongoDB Atlas迁移所需要的test,并且还避免了多个连接。但是,由于旧数据库无需进行猫鼬管理,因此我也在.db结尾处(const v1 = mongoose.connection.useDb('test').db)。
Polv

37

作为一种替代方法,Mongoose确实在默认实例上导出了新实例的构造函数。所以这样的事情是可能的。

var Mongoose = require('mongoose').Mongoose;

var instance1 = new Mongoose();
instance1.connect('foo');

var instance2 = new Mongoose();
instance2.connect('bar');

当使用单独的数据源时,以及当您要为每个用户或请求拥有单独的数据库上下文时,这非常有用。您将需要小心,因为这样做时可能会创建很多连接。确保在不需要实例时调用断开连接(),并限制每个实例创建的池大小。


1
这是写“以上答案”的另一种方式吗?
pravin

11
这不是上面的答案,更好。上面的答案不必要地安装了Mongoose的多个副本。
马丁·瓦德斯·莱昂

我将如何使用这种方法进行查询?
shahidfoy

2
await instance1.connection.collection('foo').insert({ foo: 'bar', }) await instance2.connection.collection('foo').insert({ foo: 'zoo', })
阿卜杜拉·巴马维

实际上,在我的情况下可以更好地工作,因为我对每个连接都有完全不同的凭据,更不用说模型和数据库了。
tzn

0

有点优化(对我来说至少)的解决方案。将其写入文件db.js,并在需要的地方使用它,然后通过函数调用进行调用,您就可以开始使用了。

   const MongoClient = require('mongodb').MongoClient;
    async function getConnections(url,db){
        return new Promise((resolve,reject)=>{
            MongoClient.connect(url, { useUnifiedTopology: true },function(err, client) {
                if(err) { console.error(err) 
                    resolve(false);
                }
                else{
                    resolve(client.db(db));
                }
            })
        });
    }

    module.exports = async function(){
        let dbs      = [];
        dbs['db1']     = await getConnections('mongodb://localhost:27017/','db1');
        dbs['db2']     = await getConnections('mongodb://localhost:27017/','db2');
        return dbs;
    };
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.