I am designing a module provides a constructor function that takes in a mongo db instance as its parameter. In my application I am trying to test this using mongoose. Since mongoose was built on mongoDB driver module, I am assuming that there is a way to retrieve the db driver object from the mongoose module.
I have a function that is failing but I am unsure to the reason why.
Update
Below is the code from my module
//authorizer.js
function Authorizer(mongoDBCon, userOptions){
this.db = mongoDBCon;
this.authorize = authorize;
this.assignOwner = assignOwner;
this.setUserPermission = setUserPermission;
this.setRolePermission = setRolePermission;
this.retrieveUserPermission = retrieveUserPermission;
this.setRolePermission = setRolePermission;
let defaultOptions = {
unauthorizedHandler: (next)=>{
let error = new Error('user has performed an unauthorized action');
error.status = 401;
next(error);
},
userAuthCollection: 'user_authorization',
roleAuthCollection: 'role_authorization',
}
this.options = _.assign({},defaultOptions,userOptions);
}
function setRolePermission(role, resource, permissions) {
let document = {
role: role,
resource: resource,
permissions: permissions,
};
//add the document only if the role permission is not found
let collection = this.db.collection(this.options.roleAuthCollection);
collection.findOne(document)
.then((result)=>console.log('in here')) //------> not printing :(
.catch(e=>{console.log(e)});
}
It needs to be imported/required in another file to configure
//authorizerConfig
let mongoose = require('mongoose');
let Authorizer = require('util/authorization/authorization');
let authorizer = new Authorizer(mongoose.connection.db);
//set admin role permissions
authorizer.setRolePermission('admin', 'users', '*');
authorizer.setRolePermission('admin', 'postings', '*');
module.exports = authorizer;
file with connection to mongo
//app.js
// Set up and connect to MongoDB:
const mongoose = require('mongoose');
mongoose.Promise = Promise;
mongoose.connect(process.env.MONGODB_URI);//MONGODB_URI=localhost:27017/house_db
I now am not seeing a log that I was hoping to see in the then() method.
Is mongoose.connection.db equivalent to the db instance returned
from MongoClient.connect ?
Doesn't mongoClient support promises?
Can you help solve my issue?
Answer:
#Neil Lunn has provided me with the answer. To sum up, mongoose.connection.db is equivalent to the db returned from MongoClient.connect. Also, I had an error because I was querying the db before it has established a connection.
Note that this seems to have changed at some point and in v5 I can access the db like this:
const res = await mongoose.connect(...);
const { db } = mongoose.connection;
const result = await db.collection('test').find().toArray();
Use the connection object to retrieve the MongoDB driver instance.
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/testdb', function (err){
if (err) throw err;
let db = mongoose.connection.db; // <-- This is your MongoDB driver instance.
});
MongoClient and the underlying node driver certainly supports promises. It will simply be that you are not referencing the correct "database object" by whatever method you are actually using.
As a demonstration:
const mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/other', // connect to one database namespace
options = { useMongoClient: true };
function log(data) {
console.log(JSON.stringify(data,undefined,2))
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
const testDb = conn.db.db('test'); // For example, get "test" as a sibling
let result = await testDb.collection('test').find().toArray();
log(result);
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})();
So what you "should" be doing is getting hold of the "connection" object from the connection, and referencing the db from that. It's likely you want the "sibling" db space of the current connection, and probably "admin" in your specific case for grabbing "authentication" details.
But here we employ the .db() method off of the Db Object in order to access a "named sibling". This is notably not an async method, just like .collection() is not async.
From there it's just a matter of implementing other methods native to the respective object from the core driver.
Related
im using mongoclient and im sure that I have connection to the database
const client = new MongoClient(uri);
const datatbaseslist = client.db().admin().listDatabases();
datatbaseslist.databases.forEach(db => {
console.log($db.name)
});
I saw that code in a video of the mongodb and its not working.
thanks
I have tried looking for other versions to that line
const datatbaseslist = client.db().admin().listDatabases();
datatbaseslist.databases.forEach(db => {
console.log($db.name)
});
because im pretty sure that the problem is there.
I think your question title is saying one thing (collections) and your code is confusing this any another (databases).
A mongodb server can have multiple databases.
A database can have multiple collections.
You connect to the server using a client.
Normally if you want to know about the databases, you would use admin(). Or to connect to a specific database (although you can connect via URI), the you use db(dbName) from the client.
Once you have a db object, you can get the collections from there.
The below code shows you how to get both databases and collections.
const { MongoClient } = require('mongodb')
async function main () {
// Set config
const uri = 'mongodb://localhost:27017'
const client = new MongoClient(uri)
try {
// Connect to the MongoDB cluster
await client.connect()
// Get databases
const databasesList = await client.db().admin().listDatabases()
for (const dbName of databasesList.databases.map(db => db.name)) {
console.log('DB: ', dbName)
// Get collections for each database
const collections = await client.db(dbName).listCollections().toArray()
console.log('Collections:', collections.map(col => col.name).join(', '))
console.log('---------------------------------------------')
}
} catch (e) {
// Handle any erros
console.error(e)
} finally {
// Always close the connection to the database when finished
await client.close()
}
}
main().catch(console.error)
I need some help with mongodb.
I just started using it, and made a Cluster called db, with a database called discord-bot with a collection called users
This should make a database entry for every user, so here is my code
const { MongoClient } = require("mongodb");
const uri = "mongodb+srv://<My username>:<My password>#<My db url>?retryWrites=true&w=majority";
const client = new MongoClient(uri);
async function run(query) {
try {
await client.connect();
const database = client.db('discord-bot');
const collection = database.collection('users');
await collection.insertOne(query);
} finally {
await client.close();
}
}
botClient.users.cache.forEach(u => {
const q = { name: u.username }
run(q).catch(console.dir);
})
I think this code should work, but it is giving me this error
TypeError: Cannot read property 'maxWireVersion' of null
I can not find anything online about that error, can somebody help me figure out what that error is and how to fix it. (Also, i am using mongodb with discord.js, incase that is neccessary info)
I use this to connect to mongo DB
const MongoClient = require('mongodb').MongoClient;
var connection;
MongoClient.connect('your-db-uri', { useUnifiedTopology: true }, async function(err, client) {
if(err)throw err
console.log("Successfully Connected")
connection = client
})
Then you can use connection variable as global for all functions
Title pretty much says it all, I've seen other answers on here, and even in the documentation, to use db.admin().listDatabases, but what I couldn't figure out was it what "db" is, since in the newer versions mongoclient only returns the client object, which you must call client.db("dbname") to get the specific db object, but how can I get a list of all of the database names??!
You can call the .listCollections() method on the db object
const _db = await mongo.getDb(MONGODB_URI); // to get the db object here
const collections = await _db.listCollections({}).toArray();
Update2
MongoClient.connect(url, function(err, client) {
// Use the admin database for the operation
const adminDb = client.db('local').admin();
// List all the available databases
adminDb.listDatabases(function(err, dbs) {
console.log(dbs.databases);
client.close();
});
});
or using async await style
const connection = await MongoClient.connect(url,
{ useNewUrlParser: true });
var dbs = await connection.db('test').admin().listDatabases();
Brand new to mongodb, but I think there must be something very fundamental I'm not getting. If I run the shell and type db.questions.count() I get 1,the 1 I created in the shell. But if I do the same thing in my app:
...
const MONGO_URL = 'mongodb://127.0.0.1:27017/';
const {MongoClient, ObjectId} = mongo;
const run = async () => {
try {
const db = await
MongoClient.connect(MONGO_URL);
const Questions = db.questions;
console.log(Questions.count());
...
I get Cannot read property 'count' of undefined. Why is this?
For what it's worth, db is defined, and the URL is the same one from the shell. Plus the server starts fine, so I assume that means the mongodb instance is running fine.
Install the "mongodb" npm module. It is the official MongoDB client for NodeJs.
// Create a Mongo Client Instace to connect to the MongoDB Database
// and perform various functions.
const MongoClient = require( 'mongodb' ).MongoClient;
// Store the URL of your MongoDB Server
const mongoURL = "mongodb://localhost:27017/";
// Stored the name of the Database you wanna connect to.
const dbName = "testdb";
// Create a new Mongo DB client that will connect to the MongoDB Server.
const client = new MongoClient(mongoURL);
// Connect the Client to the MongoDB Server.
client.connect( (err) => {
// Error handling of some sort.
if(err) throw err;
console.log( 'connected!' );
// Connect to the database you want to manage using the dbName you
// stored earlier.
const db = client.db( dbName );
// Store the name of the collection you want to read from.
// this can be created above near the dbName.
const collectionName = "testCol"
// Connect to the collection that you stored above.
const collection = db.collection( collectionName );
// Query the MongoDB database and log the results, if any.
collection.find({}).toArray( (err, docs) => {
console.log(docs);
} );
} )
To get rid of that newURLParser error, just use
const client = new MongoClient( mongoURL, { useNewUrlParser: true } );
instead of
const client = new MongoClient(mongoURL);
Here's the link to MongoDB NodeJS quickstart.
http://mongodb.github.io/node-mongodb-native/3.1/quick-start/quick-start/
Hi is there a way to switch database with mongoose?
I thought I could do it like that:
mongoose.disconnect();
mongoose.connect('localhost',db);
but it does not work I receive this error:
Error: Trying to open unclosed connection.
I do not know if it is because is asynchronous
As already stated you could do it using useDb function :
Example code :
async function myDbConnection() {
const url = 'mongodb+srv://username:password#cluster0-pauvx.mongodb.net/test?retryWrites=true&w=majority';
try {
await mongoose.connect(url, { useNewUrlParser: true });
console.log('Connected Successfully')
// Here from above url you've already got connected to test DB,
So let's make a switch as needed.
mongoose.connection.useDb('myDB'); // Switching happens here..
/**
* Do some DB transaction with mongoose models as by now models has already been registered to created DB connection
*/
} catch (error) {
console.log('Error connecting to DB ::', error);
}
}
Or if you wanted to create a complete new connection then you've to try mongoose.createConnection(). Just for reference in case of mongoDB driver you would use ::
mongodb.MongoClient.connect(mongourl, function(err, primaryDB) {
// open another database over the same connection
const secondaryDB = primaryDB.db(SECONDARY_DATABASE_NAME);
// now you can use both `database` and `database2`
...
});
Ref : mongoose multiple different connections, mongoose useDb(), mongoDB driver switch connections
It is asynchronous. If you pass a callback function to disconnect and try to connect to the next database in that callback, it will work.
Ex.
var mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/test1', function() {
console.log('Connected to test 1')
mongoose.disconnect(connectToTest2)
})
function connectToTest2() {
mongoose.connect('mongodb://localhost/test2', function() {
console.log('Connected to test 2')
process.exit()
})
}
The top-voted answer had thrown me in a loop for a few hours. To help the OP and others who may have the same issue, here's my take on the solution:
Suppose you have two databases with the same schema and you want to switch between them on the fly. Let's call them DB1 and DB2. Here's how you can go about doing that:
(async () => {
const connection = await mongoose.createConnection(url, options);
const getModel = (database) => {
const dbConnection = connection.useDb(database);
return dbConnection.model('Model', modelSchema);
};
const Db1Model = getModel('DB1');
const Db2Model = getModel('DB2');
})();
Tested on Node.js v12 and Mongoose v5.
One way you can achieve this is by appending the database name with the database URL. For eg: if you are working with localhost
mongoose.connect('mongodb://localhost:portNumber/xyz_db');
When you connect like this, all your models will be saved in the xyz_db under your model as a collection.
You should use the useDb function like so:
mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.connection.useDb('Users'); # Change the string to the name of the database you want to use