Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose - multiple database connections

I want to understand how to switch between databases within mongoose global promise connection.

My current connection is established this way app.ts

import * as mongoose from 'mongoose';

...

try {
    await mongoose.createConnection(`mongodb://localhost:27017/db1`, {
        useNewUrlParser: true,
    })
    console.log("Connected")
} catch (error) {
    console.log(error)
}

And then I am accessing it in different files some.model.ts

import { Schema, Document, model } from 'mongoose';

const SomeSchema: Schema = new Schema({
  name: { type: String, required: true },
  owner: { type: string, required: true }
});
export default model('Some', SomeSchema);

According to documentation.

So far we've seen how to connect to MongoDB using Mongoose's default connection. At times we may need multiple connections open to Mongo, each with different read/write settings, or maybe just to different databases for example. In these cases we can utilize mongoose.createConnection() which accepts all the arguments already discussed and returns a fresh connection for you. const conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options);

I can create multiple database connections like this

try {
const db1 = await mongoose.createConnection(`mongodb://localhost:27017/db1`, {
    useNewUrlParser: true,
})
const db2 = await mongoose.createConnection(`mongodb://localhost:27017/db2`, {
    useNewUrlParser: true,
})
    console.log("Connected")
} catch (error) {
    console.log(error)
}

I can see both connection in console.log(mongoose.connections)

But how can I specify what database should be used for the Model in some.model.ts?

import { Schema, Document, model } from 'mongoose';

const SomeSchema: Schema = new Schema({
  name: { type: String, required: true },
  owner: { type: string, required: true }
});

export default SPECIFY_DATABASE.model('Some', SomeSchema);

I have found other questions like this but there are connections created "localy", I need to use mongoose connection across many different files.

Thank you for answers, if you need more explanation please let me now.

like image 852
Raold Avatar asked Sep 03 '26 02:09

Raold


1 Answers

You need to actually return the connection, and then register a given model to each of the connections. To clarify, you need:

  • something to create a (named, specific) connection
  • schemas
  • you create models by registering schemas to the given connections,
  • you also need something to orchestrate it.

Example, lets have a "db.js" file (I call mine "repo.js" usually) with a single export, a function that returns the initialized database Promise. You'd use it by importing the function and awaiting for the db.

I have a bit of a longer example, so error handling etc is ommited for brevity.

import { createConnections } from './create-connections';
import { UsersSchema } from './users-schema';
import { PostsSchema } from './posts-schema';

let db: any;

export function getDatabase(): Promise<any> {
    if (this.db) return Promise.resolve(db);
    return createDatabases();
}

async function createDatabases() {
    const { db1, db2 } = await createConnections('mongodb://localhost/db1', 'mongodb://localhost/db2');
    const UserModel = db1.model('users', UserSchema);
    const PostModel = db2.model('posts', PostSchema);
    db = {
      UserModel,
      PostModel,
      // also if you need this
      connections: {
        db1,
        db2,
      }
    }
    return db;
}

Now, I've used './create-connections' here, which is almost what you have:

// create-connection.js
const { createConnection } = require('mongoose');

// You create connections by calling this function and giving it the URL to the server
export function createConnections(url1, url2) {
  const db1 = await createConnection(url1);
  const db2 = await createConnection(url2);
  return {
    db1,
    db2
  }
}

Now, let's say you have two models: users and posts, let's have their schemas.

// users schema
import { Schema, Document } from 'mongoose';
export const UserSchema: Schema = new Schema({
  name: { type: String, required: true },
});

// posts schema
import { Schema, Document } from 'mongoose';
export const PostSchema: Schema = new Schema({
  text: { type: String, required: true },
  owner: { type: SchemaID, required: true }
});

So now you need to bind it all in that fdirst file.

But how to use it? As I've said, since it's async, you always import it and use it as a simple async getDB:

// some controller, route handler, service etc.
import { getDatabase } from './get-database';

router.get('/users', async (req, res) => {
  const User = await getDatabase().UserModel;
  const users = await User.find();
  return res.json(users);
});

router.post('/posts', async (req, res) {
  const { text } = req.body;
  const owner = req.user.id;
  const Post = await getDatabase().PostModel;

  const post = await Post.create({ text, owner });
  return res.json(post);      
});
like image 106
Zlatko Avatar answered Sep 04 '26 18:09

Zlatko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!