单个node.js项目中的Mongoose和多个数据库

Posted

技术标签:

【中文标题】单个node.js项目中的Mongoose和多个数据库【英文标题】:Mongoose and multiple database in single node.js project 【发布时间】:2021-07-18 20:38:49 【问题描述】:

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

Mongoose 不允许在单个 mongoose 实例中使用多个数据库,因为模型是建立在一个连接上的。

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

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

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

我想知道是否有使用 mongoose 的多个数据库或任何解决此问题的方法?因为我认为猫鼬非常容易和快速。或者任何其他模块作为推荐?

【问题讨论】:

【参考方案1】:

单个 node.js 项目中的 Mongoose 和多个数据库

使用 useDb 来解决这个问题

例子

//product databse 
const myDB = mongoose.connection.useDb('product');
module.exports = myDB.model("Snack", snackSchema);
//user databse
const myDB = mongoose.connection.useDb('user');
module.exports = myDB.model("User", userSchema);

【讨论】:

这应该是最好的解决方案。一个连接访问多个数据库【参考方案2】:

稍微优化(至少对我而言)的解决方案。 将其写入文件 db.js 并在任何需要的地方使用它,并通过函数调用调用它,你就可以开始了。 p>

   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;
    ;

【讨论】:

如何使用这种方式创建模态?【参考方案3】:

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

在现实生活中,您很有可能将模型拆分为不同的文件。你可以在你的主文件中使用这样的东西:

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 是您的数据库名称。

【讨论】:

谢谢 - 我能够在一个应用程序中使用 3 个不同的数据库,使用: const mongoose = require('mongoose'); const Schema = mongoose.Schema; const mySchema = new Schema (); const mydbvar = mongoose.connection.useDb('mydb') module.exports = mydbvar.model('myCollection', MySchema); 绝对是最好和最真实的例子。连接到默认数据库(就像您使用 SQL Server 之类的东西一样),然后利用 useDb 将您的 DML 定位到适当的数据库。 (对于将用户保存在一个数据库中并将数据保存在另一个数据库中非常有帮助。)当您最终将请求发送到同一台服务器时,无需开始建立多个连接。现在,如果您要连接到两个不同的服务器,那就是另外一锅鱼了。 正如@Wade 所说,据我了解,此解决方案仅在所有数据库都位于同一服务器上时才有效。目前尚不清楚这是否回答了 OP 的问题,而且 IMO 有点误导。 这正是我从 test 迁移 MongoDB Atlas 所需的,也是为了避免多个连接。但是,我最后也是.db (const v1 = mongoose.connection.useDb('test').db),因为旧数据库不需要猫鼬管理。 当 db 在同一台服务器中时看起来很棒...当 db 在不同主机中时是否有类似的方法?【参考方案4】:

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

-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

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

【讨论】:

这意味着每个项目都有自己的连接。您将无法管理 100k 连接。我认为最好使用使用相同连接池的useDb 命令。 xpepermint 你能展示一个 useDb 的例子吗——我目前有这个问题***.com/questions/37583198/… 这看起来对项目来说是一个巨大的负担。你不这么认为吗? 每个应用程序有几个不同的连接实例(例如,用于用户数据库、会话数据库和应用程序数据)绝对没问题。这不是“巨大的负担”,也不会导致扩展问题,而是一个常见的用例。 你是我最好的朋友!非常感谢!这个对我有用!谢谢!【参考方案5】:

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

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

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

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

这在处理单独的数据源时非常有用,并且当您希望为每个用户或请求拥有单独的数据库上下文时也是如此。您需要小心,因为这样做时可能会创建很多连接。确保在不需要实例时调用 disconnect(),并限制每个实例创建的池大小。

【讨论】:

这是写'Above Answer'的另一种方式吗? 这不是上面的答案,更好。上面的答案不必要地安装了多个 Mongoose 副本。 如何使用这种方法进行查询? await instance1.connection.collection('foo').insert( foo: 'bar', ) await instance2.connection.collection('foo').insert( foo: 'zoo', ) 事实上在我的情况下工作得更好,因为我对每个连接都有完全不同的凭据,更不用说模型和数据库了。【参考方案6】:

根据the fine manual,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' 
));

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

【讨论】:

是的,我认为命名连接和共享模式是要走的路。根据 Robert 的示例,每个连接都需要一个唯一的模型。 另外结帐useDb()在3.8中可用以共享底层连接池:github.com/LearnBoost/mongoose/wiki/… 假设我有自动生成的数据库(说 n 个数据库)。不是一两个。有什么方法可以连接到这些而不为每个数据库创建单独的模型? @AnoojKrishnanG 我不认为这是可能的,不。您需要分别针对每个数据库创建模型。但是,正如我在回答中已经说过的,您可以在连接之间共享 模式,这可能会节省一些编码时间。 您可以在不同的模型之间共享架构,从而在数据库之间共享。 var newSchema = new mongoose.Schema( ... ), var model2 = conn1.model('newModel', newSchema), var model2 = conn2.model('newModel', newSchema)

以上是关于单个node.js项目中的Mongoose和多个数据库的主要内容,如果未能解决你的问题,请参考以下文章

Node.js 和 Mongoose 正则表达式查询多个字段

如何在 Mongoose/Node.js 中同时保存多个文档?

Node.js/mongoose - 数组中的子文档不会删除/移除

Node.js/mongoose - 数组中的子文档不会删除/移除

在单个响应中返回 mongoose 错误列表

Mongoose 和 Node JS 项目的文件结构