passing mongoose as an argument to a function - node.js

I'm developing a node module. I need to pass the mongoose to my module to get three things (mongoose.connection, mongoose.connection.db, mongoose.mongo) out of it.
index.js (myModule - the module I developed)
function myModule(mongoose) {
var db = mongoose.connection;
var gfs = gridfsLockingStream(mongoose.connection.db, mongoose.mongo);
this.someFunction = function() {//some code here}
}
module.exports = myModule;
db.js (A user must use myModule like this)
var mongoose = require('mongoose');
var myModule = require('myModule');
var dbUrl = 'mongodb://localhost:27017/gfsTestDB';
mongoose.connect(dbUrl);
var readyObj = new myModule(mongoose);
module.exports = readyObj; // so that the user can use this everywhere
Then the user can use readyObj to do his/her work.
My problem is that only mongoose.connection is available in myModule function and I get this error(gridfsLockingStreamn cause the error):
Error: missing db argument
new Grid(db, mongo)
I'm using :
"mongodb": "3.0.4",
"mongoose": "4.11.6",
"gridfs-locking-stream": "1.1.1",
"gridfs-stream": "1.1.1",
One solution (idea from #GrégoryNEUT) (but I think it's not the correct way):
index.js no changes
db.js using promise and mongoose event handler
var mongoose = require('mongoose');
var myModule = require('myModule');
var dbUrl = 'mongodb://localhost:27017/gfsTestDB';
mongoose.connect(dbUrl);
module.exports = new Promise(function (resolve, reject) {
mongoose.connection.on('connected', function () {
var readyObj = new myModule(mongoose);
resolve(readyObj);
});
});
photoRouter.js (one of the user's files - the user want to use readyObj)
var readyObj = require('./db').then(function (readyObj) {
// then the user uses readyObj
}
Can the code be improved?

Looking at the documentation of mongoose connect
You can use of Promises.
var mongoose = require('mongoose');
var myModule = require('myModule');
var dbUrl = 'mongodb://localhost:27017/gfsTestDB';
mongoose.connect(dbUrl)
.then(
// The connection is ready to use!
() => {
var readyObj = new myModule(mongoose);
// ...
},
// Handle the connection error
(err) => {
// ...
},
);
You can use of Callbacks
var mongoose = require('mongoose');
var myModule = require('myModule');
var dbUrl = 'mongodb://localhost:27017/gfsTestDB';
mongoose.connect(dbUrl, (err) => {
if (err) {
// Handle the error
// ...
return;
}
// We get successfully connected to the database
var readyObj = new myModule(mongoose);
// ...
});

Related

showing undefined when trying to access the collection using nodejs

i am trying to display all the documents in a collection called tutorial so i am using a simple code here's my code
const mongodb = require("mongodb");
const express = require("express");
var app = express();
var mongoClient = mongodb.MongoClient;
var conn = "mongodb://localhost:27017";
mongoClient.connect(conn, (err, client) => {
if (err) {
console.log(err);
} else {
console.log("connection estableshed");
var db = client.db("mydb");
var collection = db.collection("tutorial");
collection.find().toArray((err, data) => {
console.log(data);
});
client.close();
}
});
but the result i got undefined so what seems to be the problem here?
Problem with the callback, you can use then() method instead.
const mongodb = require("mongodb");
const express = require("express");
var app = express();
var mongoClient = mongodb.MongoClient;
var conn = "mongodb://localhost:27017";
mongoClient.connect(conn).then((err, client) => {
if (err) {
console.log(err);
} else {
console.log("connection established");
var db = client.db("mydb");
var collection = db.collection("tutorial");
collection
.find()
.toArray()
.then((data) => {
console.log(data);
});
client.close();
}
});
app.listen(3000, () => {
console.log("Server started");
});

Cannot read property 'db' of undefined after defining MongoClient.connect() outside of app.js

Previously I had a working, single-file, application that was essentially:
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const io = require('socket.io')(server);
app.set('socketio', io);
import { MongoClient } from 'mongodb';
var mongo_client;
var connection_string = 'mongodb://localhost:27017' // for local development environment
MongoClient.connect(connection_string, (err, client) => {
if (err) {
throw err;
} else {
mongo_client = client;
}
});
/*
lots of middleware and route handling
*/
server.listen(PORT, () => {
console.log(`running on port ${PORT}`);
});
In middleware, within the same file, I would make a call to the database with something like:
var collection = mongo_client.db('users').collection('users');
var query = { };
var options = { };
try {
var user = await collection.findOne(query, options);
return user;
} catch (err) {
console.log('error: ' + err);
}
I'm in the process of refactoring and have put the MongoClient.connect() block in its own file.
config/database.js now looks like:
const MongoClient = require('mongodb').MongoClient;
const { connection_string } = require('./environment_variables');
let mongo_client;
MongoClient.connect(connection_string, (err, client) => {
if (err) {
throw err;
} else {
mongo_client = client;
console.log('FIRST: mongo_client: ');
console.log(mongo_client);
}
});
console.log('SECOND: mongo_client: ');
console.log(mongo_client);
module.exports = mongo_client;
To begin testing how to import it into another file, I am doing this in app.js:
const mongo_client = require('./config/database');
app.get('/', async (req, res) => {
const query = { username: 'my name' };
const collection = mongo_client.db('users').collection('users'); // <----- error is here, mongo_client is undefined
const result = await collection.findOne(query);
res.json({ result: result });
});
(note, when I better understand how all this works, I will move the route and middleware handling out of app.js)
The console logs are:
SECOND: mongo_client:
undefined
FIRST: mongo_client:
MongoClient {
// ... lots of mongodb client properties here
}
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'db' of undefined
So it seems like MongoClient.connect() is asynchronous and therefore mongo_client is not defined before I try and call mongo_client.db('users').collection('users').
My questions are:
How can this issue be resolved?
Why wasn't it happening before I extracted MongoClient.connect() out of app.js?
I've been reading articles like these:
MongoClient connection pooling
MongoClient docs
But they seem to either:
Include subsequent calls to the database within the MongoClient.connect() function block (and i can't wrap my whole app within that function) OR
They call app.listen() within the MongoClient.connect() function block (and this is also not feasible as I do several things with express() and http and socket.io)
Environment:
node v14.18.1
"mongodb": "^4.1.4" (native driver)
Edit:
I tried the following changes in config/database.js per this article.
I replaced this:
const MongoClient = require('mongodb').MongoClient;
const { connection_string } = require('./environment_variables');
let mongo_client;
MongoClient.connect(connection_string, (err, client) => {
if (err) {
throw err;
} else {
mongo_client = client;
}
});
module.exports = mongo_client;
with this:
const MongoClient = require('mongodb').MongoClient;
const { connection_string } = require('./environment_variables');
const mongo_client = new MongoClient(connection_string);
const is_this_the_right_thing_to_do = async () => {
await mongo_client.connect();
};
is_this_the_right_thing_to_do();
module.exports = mongo_client;
The error went away and it is returning a result, but I am not sure if this is the correct way to do it.
Also, I am not sure how I can use the single instance of mongo_client in all routes and middleware. I tried requiring it at the top of app.js, hoping that the routes and middleware (in other files) that were required afterwards would have access to it, but they don't, this was the error in the route middleware:
UnhandledPromiseRejectionWarning: ReferenceError: mongo_client is not defined
Another edit:
I've posted an answer on someone else's question here which may be what I am looking for, will update this post after further testing.
If you are trying to access database (mongo_client.db("your database name here") in your case) from other routes then you can maybe try something like this in your app.js or index.js.
const connectDB = async () => {
await client.connect();
db = client.db("greendeckData");
app.use((req, res, next) => {
req.db = db;
next();
});
app.use("/get", getRouter);
};
You can check the source from where I found the solution link, here

module.find() is not a function

i have a pre-existing collection (which is on mongodb atlas), and i've connected it and cerate Modules and Schemas, and i can console log it , so far so good, but when i export the module to index.js i can't console log the data it say Model.find is not a fucntion.
PS.
i'm new to this
My code:
var mongoose = require('mongoose');
var uri = 'mongodb+srv://USER:PASSWORD#wt-cluster-xd7ou.mongodb.net/test?
retryWrites=true'
mongoose.connect(uri, {dbName: 'dbName'});
mongoose.Promise = global.Promise;
var connection = mongoose.connection;
connection.on('error', console.error.bind(console, 'connection error:'));
connection.once('open', function () {
var menuSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
category: String,
food_name: String,
food_desc: String,
food_price: String
});
var Menu = mongoose.model('Menu', menuSchema, 'menu');
Menu.find(function(err, menus){
if(err) return console.err(err);
console.log(menus);
})
module.exports = Menu;
});
this console log my data correctly
index.js
var express = require('express');
var router = express.Router();
var Menu = require('../models/menu')
var assert = require('assert')
/* GET home page. */
router.get('/', function(req, res, next) {
Menu.find({}, function (err,menus) {
assert.equal(err,null);
res.send(menus);
});
});
module.exports = router;
here is where i'm trying to send the data to the HTML
It appears you are defining and exporting your model inside the connection.on() function. Try defining those in a separate file and see if that helps.
Create your model in a separate file.
var mongoose = require('mongoose');
let connection = require('connnection.js')
var menuSchema = new mongoose.Schema({
_id: mongoose.Schema.ObjectId,
category: String,
food_name: String,
food_desc: String,
food_price: String
});
var Menu = mongoose.model('Menu', menuSchema, 'menu');
Menu.find(function(err, menus){
if(err) return console.err(err);
console.log(menus);
})
module.exports = Menu;
Change your db connection to
var mongoose = require('mongoose');
var uri = 'mongodb+srv://USER:PASSWORD#wt-cluster-xd7ou.mongodb.net/test?
retryWrites=true'
mongoose.connect(uri, {dbName: 'dbName'});
mongoose.Promise = global.Promise;
var connection = mongoose.connection;
connection.on('error', console.error.bind(console, 'connection error:'));
connection.once('open', function(){
console.log('Database ready.')
})
module.exports = connection
Save this as connection.js for require to work.
Test the route again.

Mongoose find query is not executing

I am trying to fetch some data from a mongodb. I am able to fetch the details from the model MyModel (defined in Server.js). But I can't execute the find method in the model Skill (defined in Skill.js).
Server.js
let express = require('express');
let app = express();
var config = require('./config/config');
let bodyParser = require('body-parser');
var mongoose = require('mongoose');
var cors = require('cors')
var path = require("path");
let Skill = require('./app/models/Skill');
const dbURI = config.dbURI;
app.use(cors());
app.use(bodyParser.json(true));
mongoose.connect(dbURI, {useNewUrlParser: true});
mongoose.connection.on('connected', function () {
console.log("Connected");
});
var MyModel = mongoose.model('Test', new Schema({ name: String
}));
Skill.findOne(function(error, result) {
console.log("1",error,result);
});
MyModel.findOne(function(error, result) {
console.log("2",error,result);
});
app.listen(config.appPort,function () {
console.log('App running on port :: "' + config.appPort.toString() + '"');
});
app/models/Skill.js
var mongoose = require('mongoose');
var skillSchema = new mongoose.Schema({
name: String,
length: String,
});
var Skill = mongoose.model('Skill', skillSchema,'Skill');
module.exports = Skill;
Output
App running on port :: "8080"
Conneccted
2 null { _id: 5c6678215c50a65e59fc6a89, name: 'test', __v: 0 }
I haven't found any issues while creating the schema. Could someone help me to resolve the issue?
I can't test my suggestion at the moment, but one thing I noticed in your code is that you queries, as in
Skill.findOne(function(error, result) {
console.log("1",error,result);
});
MyModel.findOne(function(error, result) {
console.log("2",error,result);
});
are not executed in the "connected" callback; may be it's not the main problem, but I would try to change the code as follows:
mongoose.connection.on('connected', function () {
console.log("Connected");
Skill.findOne(function(error, result) {
console.log("1",error,result);
});
MyModel.findOne(function(error, result) {
console.log("2",error,result);
});
});
The key thing is that each call (.on, .findOne) starts a promise, which encapsulates an asynchronous behaviour. I you place ,findOne invocation just after .on invocation, you can't be sure Mongoose's connection is ready when you starts .findOne...

One mongo connection in multiple Node modules

I am trying to have all my Node modules share one Mongo connection, and am having trouble doing so. I've looked at some of the materials written about this already. Below is the main file, the Mongo helper file, and another file that tries to use the connection. The trouble is that when the route file tries to use the Mongo connection, db is null.
Mongo helper file:
var mongo = require('mongodb').MongoClient
var _db
function connect(callback) {
const host = '---'
const database = '---'
const user = '---'
const pass = '---'
const uri = 'mongodb://' + user + ':' + pass + '#' + host + '/' + database
mongo.connect(uri, (err, client) => {
console.log('Connected to Mongo')
_db = client.db(database)
return callback(err)
})
}
function db() {
return _db;
}
module.exports = {
connect: connect,
db: db
}
Main file:
var express = require('express')
var app = express()
var mongo = require('./helpers/mongo')
mongo.connect((err) => {
if (err !== null) {
console.log("Error connecting to Mongo: " + err)
process.exit()
}
})
var problems = require('./routes/problems.js')
app.use('/problem', problems)
app.listen(3000)
Route file:
var express = require('express')
var router = express.Router()
var db = require('../helpers/mongo').db()
router.get('/stuff', (req, res) => {
var problems = db.collection('problems')
res.send('working correctly')
})
module.exports = router
What about mongoose?
const mongoose = require('mongoose');
// connect to the database (mongodb)
mongoose.connect('mongodb:<host>/<db>', {useMongoClient: true});
mongoose.promise = global.Promise;
var db = mongoose.connection;
// Check for DB connection
db.once('open', function(){
console.log('Connected to Mongo Db');
});
// Check for DB errors
db.on('error', function(err){
console.log(err);
});

Resources