The question is about architecture.
I got a module 'db', which establishes connection to mongodb and has a class with schemas, models etc. I export exemplar of that class.
Should i just require('db') in every route file or just do this in one:
server.on('request', function(req) {
req.db = db;
});
db.js:
"use strict";
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var conn = mongoose.connection;
conn.on('error', console.error.bind(console, 'connection error:'));
conn.once('open', function() {
console.log("Connected to MongoDB.");
});
class db {
constructor() {
//Users
this._usersSchema = mongoose.Schema(
{
username: String,
password: String,
email: String
});
this.Users = mongoose.model("Users", this._usersSchema);
}
}
module.exports = new db();
I think you will find differing opinions, but I prefer to require wherever I need it. modules in node are singletons, so you are always getting the same instance. And I like to separate out my controller logic into their own files away from the routes. Moreover the logic does not expect the complete request and response objects. The reason is I can then use the same code to grab data necessary to serve an API endpoint or render the view server-side without having the mock an entire request and response object.
Related
I am getting started with mongoDB and I have to say that the official documentation is not that great to see how to implement it with nodejs.
I don't really know how to structure my server file to add mongoClient.connect, should my whole server be written inbeetwen the mongoClient.connect function in order to have access to the db, like in this boilerplate? I am using nodeJS/express.
If you know any good boilerplate, or anything, that could show me the structure of a backend with an implementation of mongoDB, I would really appreciate it. Every time I find something about mongoDB, it is actually about mongooooose!!
After further reasearch, here is what I was looking for, for those who wonder like me how to implement MongoDB (and not mongoose) with Express:
var express = require('express');
var mongodb = require('mongodb');
var app = express();
var MongoClient = require('mongodb').MongoClient;
var db;
// Initialize connection once
MongoClient.connect("mongodb://localhost:27017/integration_test", function(err, database) {
if(err) throw err;
db = database;
// Start the application after the database connection is ready
app.listen(3000);
console.log("Listening on port 3000");
});
// Reuse database object in request handlers
app.get("/", function(req, res) {
db.collection("replicaset_mongo_client_collection").find({}, function(err, docs) {
docs.each(function(err, doc) {
if(doc) {
console.log(doc);
}
else {
res.end();
}
});
});
});
I've found several ways of doing it, even in mongoDB's official pages.
By far, I prefer this one (not mine, source below) where you instantiate the connection in one file and export it and the database/client to the server file where express is instantiated:
(I copied only what's important, without error handling)
// database.js
const MongoClient = require('mongodb').MongoClient;
let _db; //'_' private
const mongoConnect = function(callback) {
MongoClient.connect(
'mongodb://localhost:27017',
{ useUnifiedTopology: true }
)
.then(client => {
_db = client.db('onlineshopping');
callback();
})
.catch(error => {
console.log(err);
throw new Error('DB connection failed...');
});
}
const getDB = () => {
if (_db) {
return _db;
} else {
throw new Error('DB connect failed');
}
}
exports.mongoConnect = mongoConnect;
exports.getDB = getDB;
// index.js
const express = require('express');
const app = express();
const mongoConnect = require('./util/database').mongoConnect;
// ...
mongoConnect(() => {
app.listen(3000);
})
Source:
https://github.com/TinaXing2012/nodejs_examples/blob/master/day9/util/database.js
Corresponding to this YouTube course that I recommend in this topic: https://www.youtube.com/watch?v=hh-gK0_HLEY&list=PLGTrAf5-F1YLBTY1mToc_qyOiZizcG_LJ&index=98
Other alternatives from mongoDB official repos, are:
https://github.com/mongodb-developer/mern-stack-example
https://github.com/mongodb-developer/nodejs-quickstart
I'm building a restful web service api using NodeJS.It uses Mongoose as ODM and using MongoDB for backend.
Below i will explain my scenario
I started nodejs server
After that i shutdown the MongoDB database.
Then call the GET api call,it doest catch any errors and api call get hang.
database config in main.js file
var mongoose = require('mongoose');
var uri = 'mongodb://localhost/mydb';
mongoose.Promise = global.Promise;
var options = { server: {socketOptions: { keepAlive: 300000, connectTimeoutMS: 10000 } } } ;
mongoose.connect(uri,options);
var db = mongoose.connection;
db.on('error',console.log.bind(console,'connection refused !!!!!'));
db.once('open', console.log.bind(console,'connection success !!!!!'));
this is my basic GET call
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var rootRes = require('../model/rootresources.js');
router.get('/', function(req, res, next) {
rootRes.find({},function (err, rootResource) {
if (err){
console.log('Error occurd !!!') }
res.json(rootResource);
});
});
Even database connection failed, the code does not goes to error block. So didn't capture the database refuse when database connection is failed in the API call.
I want to capture that error and send internal server error (code:500) to client. I tried to find the solution but still could not find it
Any solutions or do i made a mistake ?
Thank you
Amila
Did you put the two parts of code in the same file(ie. main.js) or two different files.
put them in the same file, and run node main.js do throw exceptions.
// main.js
var mongoose = require('mongoose');
var uri = 'mongodb://localhost/mydb';
mongoose.Promise = global.Promise;
var options = { server: {socketOptions: { keepAlive: 300000,
connectTimeoutMS: 10000 } } } ;
mongoose.connect(uri,options);
var db = mongoose.connection;
db.on('error',console.log.bind(console,'connection refused !!!!!'));
db.once('open', console.log.bind(console,'connection success !!!!!'));
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var rootRes = require('../model/rootresources.js');
router.get('/', function(req, res, next) {
rootRes.find({},function (err, rootResource) {
if (err){
console.log('Error occurd !!!') }
res.json(rootResource);
});
});
exceptions are:
connection refused !!!!! { MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]
etc...
So, I think maybe you put codes about express in a file like index.js and codes about mongoose connection in another file. And just run node index.js in command line. While running codes in index.js will not include codes in other files, codes in main.js will not be executed. As the result, there is no error info.
Updates
Two ways of I know two ways of doing this:
1.In main.js create function which creates connection to database and returns a instance of db so that you can call it function in you main code.
// main.js like this
var mongoose = require('mongoose');
function createConnection(url) {
mongoose.connect(url,options);
var db = mongoose.connection;
db.on('error',console.log.bind(console,'refused !!!!!'));
db.once('open', console.log.bind(console,'success !!!!!'));
return db;
}
// export function
module.exports = createConnection;
// in your index.js
var createConnection = require('./main.js');
var db = createConnection(url);
// other codes here
2.Using require or vm to compile and run javascipt code. You can find vm api detail here
//main.js
var mongoose = require('mongoose');
var uri = 'mongodb://localhost/mydb';
mongoose.Promise = global.Promise;
var options = { server: {socketOptions: { keepAlive: 300000,
connectTimeoutMS: 10000 } } } ;
mongoose.connect(uri,options);
var db = mongoose.connection;
db.on('error',console.log.bind(console,'connection refused !!!!!'));
db.once('open', console.log.bind(console,'connection success !!!!!'));
// index.js
// require will load file and execute automaticly
var scriptSrc = require('./main');
// other codes here
You can think of the second way as using eval('var mongoose = require('mongoose');
var uri = 'mongodb://localhost/mydb'; etc...)
mongoose connection do not happen unless you hit a request. so its best you handle it in your first request middleware. see code insight bellow.
module.exports = function () {
return function (req, res, next) {
mongoose.connect(URL, MONGO_OPTIONS);
mongoose.connection
.once('open', () => { })
.on('error', (error) => {
res.status(401).json({});
});
...
Then pass the middleware above to your router: let me know if you need more explanation
router.get('/', myMiddleware(){})
I'd like to know how to work with connectivity to a database in MEAN stack application. In particular, when should I create a connection to a database and when should I destroy a connection to a database. Should I create and destroy a connection on every new HTTP request or should I store a once created connection and use it for any subsequent requests as long as possible. I use Mongoose as a modeling tool.
Here is an example.
This is my routes.js file with a route /index. A request to this route should fetch some date from MongoDb database. It bothers me how I connect and disconnect to a database now. Yes, I connect and disconnect to a database exactly as written in Mongoose docs, but it it the right way to do it in a serious production environment?
var express = require('express');
var router = express.Router();
var config = require('./db-config');
// I create a Mongoose instance as a module object,
// as opposite to create it in every request handler function below.
var mongoose = require('mongoose');
var productSchema = require('../db/productSchema'); // model schema is also a module-wide object
// And here is a request handler function.
// It is called on every request as a brand new.
// I create and destroy a database connection inside this request handler
router.get('/index', function(req, res, next) {
// I connect to a database on every request.
// Do I need to do it here in a request handler?
// May I do it outside of this request handler on a module-wide level?
mongoose.connect('mongodb://my_database');
// I create a new connection here in a request handler.
// So it lives only during this request handler run.
// Is this the right way? May I do it outside of this request handler
// on a module-wide level and somehow keep this connection and use it
// in every subsequent requests to this or any other route in the app?
var db = mongoose.connection;
db.on('connecting', function() {
console.log('connecting');
});
db.on('connected', function() {
console.log('connected');
});
db.on('open', function() {
console.log('open');
});
db.on('error', console.error.bind(console, 'connection error'));
db.once('open', function(cb) {
var Product = mongoose.model('Product', productSchema);
Product.find({category: "books"}, function(err, prods) {
if (err) return console.error(err);
// I close a connection here in a callback.
// As soon as successfully fetched the data.
// Do I need to close it after every request?
// What is the right place and time to do it?
db.close(disconnect);
res.json(prods);
});
});
})
Found some good answers:
https://softwareengineering.stackexchange.com/questions/142065/creating-database-connections-do-it-once-or-for-each-query
What are best practices on managing database connections in .NET?
Its best practice to have your db connection in a separate module (db.js)
var mongoose = require('mongoose')
mongoose.connect('mongodb://localhost/dbname', function(){
console.log('mongodb connected')
})
module.exports = mongoose
Each model should have a separate module that takes in the db connection (post.js)
var db = require('../db.js')
var Post = db.model('Post', {
username: {type: String, required: true},
body: {type: String, required: true},
date: { type: Date, required: true, default: Date.now }
})
module.exports = Post
Then whenever you need to use that data set just require it and make calls
var Post = require('/models/post')
Post.save()
Post.find()
This is an opinion based question I'd say. What I use for my app is
app.get('/', function (req, res) {
res.sendfile('index.html');
});
mongoose.connect('mongodb://localhost:27017/my_db');
This way I create a connection once rather than on every HTTP request. Your way should work fine but it seems you will have to connect and disconnect the db to your app way too many times specially when the app is in development.
You want your connection to act like a singleton so as mentioned in the answer above it makes sense to do it outside of, and preferable before your routes:
var compression = require('compression');
var express = require('express');
var app = express();
var port = process.env.PORT || 8080;
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
...
app.use(compression());
// db
var mongoose = require('mongoose');
var configDB = require('./config/database.js');
mongoose.connect(configDB.url); // connect to our database
config/database.js:
module.exports = {
'url' : '#localhost:27017/dbname'
};
This is my solution :
import express from 'express';
import mongoose from 'mongoose';
import { name } from '../package.json';
import * as localconfig from './local-config';
import debug from 'debug';
debug(name);
const app = express();
const port = process.env.PORT || 3000;
const mongoUrl = localconfig.credentials.MONGO_URL;
import usersRoutes from './routes/users/user-routes';
app.use('/v1/users', usersRoutes);
mongoose.connect(mongoUrl)
.then(() => {
debug('DB connection successful');
app.listen(port, '0.0.0.0', () => {
debug(`Running on port ${port}`);
});
})
.catch((err) => {
debug(err);
});
You should first check weather the connection is successful or not and only then listen to a certain port. This is my app.js file where all the routes are loaded, so you do not have to call the db connection in all your files. You have a single config file where all the config is done. Your router file user-routes.js will look something similar to this:
import express from 'express';
import User from '../models/user'
const router = express.Router();
router.get('/', (req, res, next) => {
User.find()
.then((response) => res.json(response))
.catch((err) => next(err));
});
module.exports = router;
I am trying to connect my node app to mongodb via mongoose. It seems to be working, as I can add documents, but I get the error { [Error: Trying to open unclosed connection.] state: 2 }.
I created a very simple app, just to make sure everything is working properly before connecting my actual app.
Here is my simple app:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var timeSchema = new Schema({ timestamp: String });
var Time = mongoose.model('Time', timeSchema);
mongoose.connect('mongodb://localhost/mydb');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error: '));
db.once('open', function () {
var testA = new Test({ timestamp: Date() });
});
I also tried adding db.close() to the end, but it made no difference.
This is running on a Ubuntu 14.04 VPS with:
Node.js v0.10.3
MongoDB 2.6.3
Mongoose 1.4.21
In my opinion, you are trying to create another connection without closing the current one. So, you might want to use:
createConnection() instead of connect().
In your case, it would look like this:
db = mongoose.createConnection('mongodb://localhost/mydb');
I had the same issue and found that I had the below connection in another file, which was the reason why I couldn't connect with a different database name. The below createConnection is needed:
db = mongoose.createConnection('mongodb://localhost/mydb');
What I had in another file:
db = mongoose.Connection('mongodb://localhost/mydb');
just use mongoose.connect('...'); once.
maybe in your root app.js or index.js file, not in every model or database related files if your are importing (including) them.
Anyways, if you still have doubt you can check it by:
var mongoose = require('mongoose');
var db = mongoose.connection;
db.once('connected', function() {
console.log('mongoDB is connected');
});
shouldn't your
db.once('open', function () {
var testA = new Test({ timestamp: Date() });
});
be
db.once('open', function () {
var testA = new Time({ timestamp: Date() });
});
If "Test" is a different schema based on a different connection, that might affect i think
I had the same issue, but it was due to a typo:
express-sessions instead of express-session
I'm new to node.js and mongodb.
I'm trying to create a schema for a User collection in a mongolab mongodb database from a node.js app with the code below. The code does not seem to be failing (at least, I get no error messages), but I don't see any indication that it is succeeding either. That is, when I go to mongolab and look at my database, I don't see that any schema was created - https://dzwonsemrish7.cloudfront.net/items/01263Y1c312s233V0R17/mongodb-schema.png?v=7fdc20e3.
Can someone explain what I might be doing wrong, or how I can verify that my code succeeded and a schema was, in fact, created for my collection?
// file: app.js
var express = require('express'),
http = require('http'),
mongoose = require('mongoose');
var app = express(),
port = 3000;
// Connect to database in the cloud (mongolab)
mongoose.connect('mongodb://username:password#ds041344.mongolab.com:41344/stockmarket');
// Create a schema for User collection
mongoose.connection.on('open', function () {
console.log(">>> Connected!");
var UserSchema = new mongoose.Schema({
username: {type: String, unique: true},
password: String
});
var UserModel = mongoose.model('User', UserSchema);
});
app.get('/', function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello, World!\n');
});
http.createServer(app).listen(port, function(){
console.log("Express server listening on port " + port + " ...");
});
You must insert a document first. Schemas are not explicitly defined in mongodb. Once you insert a document, the collection will automatically be created and you will see it in the mongolab console.
Example from http://mongoosejs.com/
var mongoose = require('mongoose');
var db = mongoose.createConnection('localhost', 'test');
var schema = mongoose.Schema({ name: 'string' });
var Cat = db.model('Cat', schema);
var kitty = new Cat({ name: 'Zildjian' });
kitty.save(function (err) {
if (err) // ...
console.log('meow');
});
after the save call above the collection will be created
Data in MongoDB has a flexible schema. Documents in the same collection do not need to have the same set of fields or structure, and common fields in a collection’s documents may hold different types of data.