I'm currently developing a web app. I just started the development and i try to setup the routes after the db (mongoose Schemas and connection) is ready because i need the models in my router.js file. My Code looks like this right now:
File: server.js
//configuration here...
mongoose.connect( "mongodb://" + config.database.host + "/" + config.database.dbName );
var db = mongoose.connection;
db.on( "error", console.error.bind(console, "connection error:" ));
db.once( "open", function () {
var allModels = models.getAll( mongoose ); //retreive models from different files
router.setupRoutes(express, app, allModels); //setup all the routes also specified in other files
console.log("connected to database and created the routes!");
});
app.listen(port, host, function() {
console.log("");
console.log("Server started at: " + "http://" + host + ":" + port);
console.log("Press 'STRG+C' to stop the Server");
console.log("");
});
My Question is:
Is that the right way to do that? I call the app.listen function not inside this once("open") function (app.listen is at the bottom of this file and gets called before the routes are set up) My test routes are working but im not accesing the mongoose models right now. Should i call app.listen in the mongoose callback or like now at the end of my file?
i just want to make sure that this is the right way to do this. it seems to be the right way. mongoose said so... Look here
I wouldn't say that there's a right or a wrong way. It depends what you're trying to do. Here are my thoughts:
Do you want to have your server running if the database connection isn't working? Maybe because some routes don't involve the database? If that's what you're aiming for, you'd have to set up the routes outside the db connection callback. Something like this:
db.once('open', function() {
// set up routes that involve db connection
});
// set up routes that don't involve db connection
app.listen(port, host, function() {
});
If all of your routes involve database communication, I don't see a purpose to having app.listen outside of the db connection callback. Because the fact that the server is listening wouldn't be useful if the database connection is broken.
I would like to point to specific case. when we put the connection in the server.js The app will try to connect when it is lunched. And If error has been occured it will throw the error and never look back. However, when we put the connection in the routes, the app will try to reach the db only when it needs to, and every time it needs to.The thing that make us able to reach db related end points and none related end points and open to db status changements. So If the db has a problem and we fix it, no need to restart the server.
Related
I googled a lot but still have no clear solution to my issue.
Connecting to MongoDB, usually you establish a connection and after the job is done you close it.
Since next.js (and probably node.js) is single threaded. Sometimes it happens that there are two requests processed async while one request established the connection to the database, the otherone is closing the exact same connection. So the first request runs into an Topology closed exception. I have the feeling that the mongodb driver client is shared.
Is there something I did not understood correct in this?
try {
await client.connect()
const database = client.db("test")
const collection = database.collection("test")
const newDataset = await collection.insertOne({})
return newDataset.insertedId.toString()
} finally {
await client.close();
}
As in the comments stated, ive seen a lot of examples & questions here on stackoverflow where in each received request (example below) a database connection is established. This has no benefits and is "bad" because it just takes time and makes no sense. E.g:
app.get("/", (req, res) => {
MongoClient.connect("...", (err, client) => {
// do what ever you want here
client.close();
});
});
If you application needs a database connection, establish the connection "in the startup phase" and keep the connection open. There is no reason to open and close the database connection for each request.
const mongodb = require("monogdb");
const express = require("express");
const app = express();
// some custom init stuff
// e.g. require your route handler etc.
mongodb.MongoClient("...", (err, client) => {
// do what ever you want with the db connection now
// e.g. monkey patch it, so you can use it in other files
// (There are better ways to handle that)
mongodb.client = client;
// or the better way
// pass it as function parameter
require("./routes")(app, client);
app.listen(8080, () => {
console.log("http server listening");
});
});
As you can see in the code above, we first create a database connection and then do other stuff. This has some advantages:
If your credentials are invalid, your application is not externeal reachable because the http server is not started
You have a single connection for all requests
Database queries are potential faster because you dont have to wait to establish first a db connection
NOTE: the code above was "inline coded" here and is not tested.
But i think its illustrated the concept behind my statement.
it is a naive question.
Say you have a config file storing all you need for making a connection to your db.
If you are reading asynchronously, is the connection done in the callback?
fs.readFile(pathToConfigFile, function (err, data){ createConnection(data);});
Does it look ugly, suspicious and bit dangerous, doesn't it?
(This is an example, but I'd like to hear some opinions about it, if and why it is worng doing that and so on)
In my case I am using mongoose, I query the db on the schema object (i.e. User.find()...) so I simply get null results because the connection doesn't happen synchronously I guess.
Thank you very much
(here is my app-structure)
app.js
db.js (read the config file and make the connection)
config.json (info of db and others)
user.js (model for users)
home.js (query all the users and list them on .get '/')
It's ok to so sync operations during app start up. However, do not do any sync stuff once the app has started, especially while handling requests.
Your app should be configured to start IF the database connectivity was successful.
// set up your app
var express = require('express')
var app = express()
....
// set up database connectiveity
var db = mongoose.connection;
db.on('error', function() {
console.log('DB connectivity error')
process.exit()
});
db.once('open', function() {
// start your app now
app.listen()
});
create config.json like this:
config.json
module.exports = {
dbUrl:"mongodb://localhost/testDB",
serverPort: 9999
// add you other config key here
}
and require config file wherever you want to use like:
var config = require("./config");
console(config, config.severPort)
Suggestion: Use config module. It will read your config file as per the environment or default config file
In my project I want to make a separate module to get mongoose connection,say connection.js ,
var mongoose = require('mongoose');
mongoose.connect('mongodb://host:port/db');
mongoose.connection.on('connected', function () {
console.log('Mongoose default connection open to localhost:27017' );
// If the connection throws an error
mongoose.connection.on('error',function (err) {
console.log('Mongoose default connection error: ' + err);
});
// When the connection is disconnected
mongoose.connection.on('disconnected', function () {
console.log('Mongoose default connection disconnected');
});
module.exports= mongoose;
which I can import using require in another file,say file1.js , as
var connect_to_mongoose = require('connection');
whenever necessary.
But I have came across the problem that since in nodejs IO is async then how can i make sure that the connection is successful and I can now use connect_to_mongoose variable for queries,insertions,deletions etc.
My second question is that after handling the above scenario how can I manage multiple connections for multiple databases. Bcoz as far as i know(for practical reasons) in mongoose one connection is dedicated to one DB only.
I think you should consider scenarios while working with mongodb and mongoose.
mongoose.connect opens a default connection as soon as app starts
you don't have to create every time a new connection if you are dealing with multiple tables / collections (whatever you call).
if you are dealing with multiple databases then you've separate your mongodb url like mongoose.connect(mongodb://localhost/db1) && mongoose.connect(mongodb://localhost/db2)
But above point no. 3 would give you an Warning : Trying to Close an open connection
To solve above issue just use the following :
var db = mongoose.createConnection(mongodb://localhost/db1)
And after your all tasks are completed close the connection
Cheers :)
I've created a basic node.js server program and used socket.io to pass some field data from a client (see below). Pretty chuffed as I'm new to this business. I liked this node-express-socket.io approach as its all Javascript and is apparently usable by most browsers (incl' mobile). The problem is I've kind of fumbled my way through and do not not fully understand what I have created! Two questions...
1) Do I need to use the "//ajax.googleapis.com...jquery..."? This is annoying as the browser will need to have an internet connection to work. Is there another way to access the html doc elements without needing an internet connection?
2) What does the "app.use(express.static...." line do? The "app.get..." function seems to require this to work.
If there are any other general comments about my code please let me have it!
Cheers,
Kirbs
Client side code:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect(document.location.protocol+'//'+document.location.host);
function clicked(){
$(function(){
var makeInput=$('.app').find('#make').val();
var modelInput=$('.app').find('#model').val();
socket.emit('make', makeInput);
socket.emit('model', modelInput);
});
};
</script>
Server side code:
var express = require('express');
var http = require('http');
var socketio = require('socket.io');
var app = express();
var server = http.createServer(app);
var io = socketio.listen(server);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.on('make', function (make) {
socket.on('model',function (model){
console.log('recieved message:', make+','+model);
});
});
});
server.listen(8000);
1) As you have setup a static web server (see answer 2), you could simply download the jquery source and serve the .js file from there.
2) "app.use(express.static...." configure a static webserver and setting up the http root directory to the directory that your node.js script lives, as indicated by the __dirname variable. For more detail, see app.use API reference.
As result, I would recommend you change you app.use to:
app.use(express.static(__dirname + '/public'));
and place all your static files, including your jquery file(s), under a public subdirectory.
Also, your server side code has a dependency on sequence of make and model which should be changed. For example, if you switch the emit order to model then make, you should see that your server's console.log will be picking up the make from the previous call.
Instead, try something like:
// On server:
socket.on('info', function (info) {
console.log('recieved message:', info.make+','+info.model);
});
// On client:
socket.emit('info', { make: makeInput, model: modelInput })
1) You can serve the jQuery library also from your server if you like that better. You should put it in the public/vendor or public/js folder in your project.
2) This is a middleware call from Express framework, which uses in turn the Connect middleware stack. Read up on this here.
I'm a noob to Node.js and Express :( I'm having an issue with accessing the socket.io object in other modules. I have created a global variable to hold a socket object however as soon as that user closes the connection the connection isn't available anymore. Technically I guess the connection still lives on but I delete it for resource reasons.
Notice below everytime a connection is made we assign that socket to the global variable which is accessible to all other modules.
// App.js
var io = require('socket.io').listen(server);
var sessionsConnections = {};
io.sockets.on('connection', function (socket)
{
global.socket = socket;
sessionsConnections[socket.id] = socket;
.....
}
socket.on("disconnect", function()
{
delete sessionsConnections[socket.id];
});
// Match.js
global.socket.emit('lobby:createMatch', data);
If the connection last assigned to the global closes Match.js will be screwed. At this point Match.js is the only module who will ever need that socket.io reference. Match.js has a bunch of exports for handling events, emitting the changes and rendering the view.
Are there any suggestions to how this is handled? Is it possible to instantiate an initial socket connection to live in App.js for the purpose of being a global reference?
The socket variable in io.sockets.on('connection', function(socket) {...}) is different for each connection.
Since in your code global.socket is always a reference to the socket relative to the last connected client, it is normal that if this client disconnects, this socket will die.
In any case, I don't see any reason to use a global variable. If you need to send a message to a specific client, you can use the socket variable inside the connection callback:
io.sockets.on('connection', function (socket)
{
socket.emit('foo', 'bar');
}
If you need to access the sockets in another module, you can export the sessionsConnections object, and access the socket you need by its id:
//In app.js
exports.connections = sessionsConnections;
//In match.js
var app = require('./app.js');
app.connections[clientId].emit('foo', 'bar');
Of course, you need to keep track of the id's somewhere.
You might try express.io,
http://express-io.org/
npm install express.io
It works the same as express, except that it has socket.io integration built-in. It also has basic routing, so that it is a little easier to deal with your issue.
Check out this simple example:
app = require('express.io')()
app.http().io()
app.io.route('some-event', function(req) {
req.io.broadcast('announce', 'someone triggered some-event')
})
app.listen(7076)
You can also do routing with objects, which makes it more like a traditional controller:
app = require('express.io')()
app.http().io()
app.io.route('posts', {
create: function(req) {
// create a post
},
remove: function(req) {
// remove a post
}
})
app.listen(7076)
Hope that helps!