First off, I am a totally new developer with regards to Node.js.
I have started creating a sample express application, and I wanted to use an additional module to learn more about it. I have installed via npm the "mysql" module, all fine.
I have added it at the beginning of app.'s, like this:
var mysql = require('mysql');
now, as you already know, express created an index.js file inside the directory routes: i would like to be able to access the mysql variable to connect to the db from this index.js page but, using the command
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
});
obviously doesn't work, giving the "500 ReferenceError: mysql is not defined".
Of course, I am sure I need to pass this variable, but I really have no clue, can any good soul enlighten me? I know this is a very small and basic thing, but I tried this already, and doesn't seem to work:
... app.get('/', routes.index, mysql); ...
and on index.js:
exports.index = function(req, res, mysql){ ...
In Node.js, you should require modules in the files you need to use them in; so, if you want to use the mysql package in your routes/index.js file, at the top of that file, do
var mysql = require('mysql');
You may end up requiring a module in more than one file; this is normal and, in many ways, a good thing (no namespacing issues, etc.)
If you want to learn more about modules and packages, you may be interested in these two screencasts:
Modules: http://nodecasts.net/episodes/3-modules
Packages & npm: http://nodecasts.net/episodes/4-packages-and-npm
Passing the mysql object through app.get() would be a normal reaction, but I'm pretty sure you're over-thinking it.
It's as simple as including var mysql = require('mysql'); at the top of routes/index.js. In fact, you may find that you don't even need to require mysql in app.js if all database interactions are done in your routes.
Related
I have a Node/Express app that uses Mongoose to talk to a MongoDB database. The Express server is configured in a file called server.js and the schema is in a separate models.js file. Following every project and tutorial I've seen so far, I have the mongoose.connect() configured in both places:
// server.js
const express = require('express');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const app = express();
mongoose.connect('mongodb://127.0.0.1/mydb');
// models.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const User = new Schema({
username: String,
password: { type: String, select: false },
name: String,
});
module.exports = mongoose.model('User', User);
My question is, since I'm already importing mongoose in models.js, can I not skip doing so in server.js entirely and just set the connection in the model script itself? What's the point of importing it and configuring a connection along with the rest of the server config when I'm only going to use it when working with the schema? And If the answer is yes, why doesn't anyone do that? Is there a performance benefit at play here?
You could do mongoose.connect() in your model script but this would not be advisable.
You would have to ensure that this model was loaded before any other scripts that required the mongoose connection.
If you go on to create another model in your application, then this would rely on your User model (model.js) having been loaded first.
You would have to perform the connection in each model just to be sure, but this would be a poor design and unnecessary code duplication.
Therefore, connecting in server.js is the best approach to ensure the connection is established as early as possible.
It is not necessary that you require the mongoose in the server.js file. In fact in my project I create a separate file for each connection like connection_one.js, connection_two.js and export the mongoose object. This way when any number of models does a require("./connection_one.js") it will return the same connection ready mongoose for all models exporting it. This is possible due to modules are cached on first time load inside a project. It is what is also happening when you are loading the mongoose module in server.js, it is the same mongoose object in server.js and model.js.
To address you question, first of all you need to understand object-oriented programming. Right now, you have two different files. One if server.js. and another is models.js. And each file has it's own scope.
Even if you imported mongoose in server.js since the two scopes has different scope set, models.js cannot utilize the mongoose service imported in server.js. For example, let say you defined a variable "foo",
You cannot use that variable in model.js because their scopes are isolated.
// server.js
const foo = 'bar';
If you want to use only one mongoose imported in a single script and shared by others, you can use global object from Node.js env. Check out the url to know more about this.
node.js global variables?
However, I don't really recommned putting mongoose service in gloabl object. Global scope can be easy at the beginning, but it could be significant scalability problem as your application grows bigger in later time.
Thanks.
All the Node.js tutorials that I have followed have put everything in one file. It includes importing of libraries, routing, database connecting and starting of the server, by say, express.js:
var app = require('express');
app.get('/somePath', blah blah);
app.listen(...);
Now, I have 4 node servers behind an Nginx load balancer. It then becomes very difficult to have the source code updated on all the four servers.
Is there a way to keep the source code out of the server creation code in such a way that I can deploy the source code on the servers as one package? The server creation code should not know anything about routing or database connections. It should only be listening to changes in a folder and the moment a new module meta file appears, it starts hosting that web application.
Much like how we deploy a Java code packaged as war by Maven and deployed to the webapp of Tomcat, because Tomcat instantiation is not part of the source code. In node.js it seems server is also part of the source code.
For now, the packaging is not my concern. My concern is how to separate the logic and how do I point all my servers to one source code base?
Node.js or JavaScript for that matter doesn't have a concept like WAR. But what it does have is something similar. To achieve something WAR like, you would essentially bundle the code into one source file using something like webpack. However, this will probably not work with Node.js modules like http (Express uses `http since it likely calls or relies on native V8/C++ functions/libraries.
You could also use Docker and think of the Docker containers as WARs.
Here is what I figured out as a work around:
Keep the servers under a folder say, "server_clusters" and put different node servers there, namely: node1.js, node2.js, node3.js, node4.js, etc (I know, in the real world, the clusters would be different VMs or CPUs altogether but for now, I simply want to separate server creation logic from source code). These files would have this code snippet:
var constants = require('./prop');
var appBasePath = constants.APP_BASE_DIR;
var appFilePath = appBasePath + "/main";
var app = require(appFilePath);
//each server would have just different port number while everything else would remain constant
app.listen(8080, function (req, res) {
console.log("server started up");
});
Create a properties file that would have the path to the source code and export the object. That simple. This is what is used on line#1 in the above code
Create the source directory project wherever you want on the machine and just update its home directory in the constant file above. The source code directory can export one landing file that will provide the express app to the servers to start:
var express = require('express');
var app = express();
module.exports = app;
With this, there are multiple servers that are pointing to the same source code.
Hope this helps to those who are facing the same problem.
Other approaches are welcome.
I'm a beginner to Node.js and I'm currently building a Node.js program that accesses and queries a Microsoft Azure SQL database with the "tedious" module (see code below) and puts the data onto a html webpage. I want to run this code in a browser so I used browserify to bundle the modules together. However, when this code is run in Google Chrome, the following error is returned: require is not defined. Is there a fix? Is it even possible to use the tedious module in Chrome? If it isn't possible, do I need to use an intermediate server between the Node.js application and the webpage?
var Connection = require('tedious').Connection;
var config = {
userName: 'hackmatch',
password: 'hackvalley123!',
server: 'hackmatch.database.windows.net',
options: {encrypt: true, database: 'AdventureWorks'}
};
var connection = new Connection(config);
connection.on('connect', function(err) {
// If no error, then good to proceed.
console.log("Connected");
});
var Request = require('tedious').Request;
var TYPES = require('tedious').TYPES;
Thanks in advance for your help! :)
No. This module can only be used in Node.
tedious depends on the node.js net module to make a connection to the database server. This module has no equivalent on the browser, as web pages cannot make arbitrary network connections.
Even if it were possible to use this module in the browser, it'd be a terrible idea. You'd be allowing anyone on your web site to connect directly to your SQL server and run SQL queries. This can only end badly.
I have a web app under development. I found CW Buechler's tutorial on how to make a simple one very useful but have a couple of niggling worries that I'd like to know whether they're real issues, or things I can ignore.
The way I connect my routes to my database is straight from the tutorials.
in app.js, this code instantiates the database, and attaches a reference to it to every req object that flows thru the middleware.
// wire up the database
var mongo = require('mongodb');
var db = require('monk')('localhost:27017/StarChamber');
----------8<-------
// Make our db accessible to our router
app.use(function(req,res,next){
req.db = db;
next();
});
And in the middleware it get used like this:
app.get('/', function (req, res) {
var db = req.db;
var collection = db.get('myCollection');
// do stuff to produce results
res.json (results);
});
So, to my niggling worries:
Passing the db to the routes by attaching it to the req is pretty convenient, but does it impact performance? Would it be better to have a reference to it in my router file that I could just use? What's the code to do this?
Is it good practice to drop the collection after its been used? The Tutorial doesn't do so, but a collection.drop() call before exiting the route handler looks beneficial, otherwise I think I'll just rack up lots of open connections with the db.
Thanks as ever!
No, it won't impact performance. It's a convenient method to pass a reference to db around, but with Monk it doesn't seem to be especially necessary. See below for an alternative setup.
You are confusing collections with connections. The former are the MongoDB-equivalent of "tables" in SQL, so dropping them doesn't seem to make sense since that would basically throw away all the data in your database table. As for connections: through various layers of indirection, Monk seems to be using the official MongoDB Node driver, which handles connections itself (by means of a connection pool). So there's no need to handle it yourself.
For an alternative way of passing the Monk database handle around: you can place it in a separate module:
// database.js
module.exports = require('monk')('localhost:27017/StarChamber');
And in each module where you require the handle, you can import it:
var db = require('./database');
Note: Please read the edited portion of this post before answering, it might save you time and answers one of my questions.
The problem I'm having is pretty simple but I'm pretty new to this overall and I'm having issues figuring out how to implement a mongodb database connection properly in a node/express app.
I'm using express 3.x and am basing my app layout around this project supplied by the author of Express:
https://github.com/expressjs/express/tree/d8caf209e38a214cb90b11ed59fd15b717b3f9bc/examples/blog (now removed from repo)
I have no interest in making a blog however the way the app is structured appears to be quite nice. The routes are separated and everything is organized nicely.
My problem is I might have 5-6 different route js files and each route js file might have anywhere between 1 and 15 routes; of those routes 1 or 15 might want to access the db.
So my problem is it seems like a really terrible idea to do a db.open(...) every single time I want to query the db. I should mention at this point I'm using the native mongo-db driver (npm install mongodb).
I would also need to include a file like this:
http://pastebin.com/VzFsPyax
...in all of those route files and all of my model files. Then I'm also dealing with dozens upon dozens of open connections.
Is there a way I can structure my app in such a way where I only make 1 connection and it stays open for the duration of the session (having a new one made every request would be bad too)?
If so, how can I do this? If you know the answer please post a code sample using tj's blog app (the one linked earlier in this post) structure as a base guide. Basically have a way where the routes and models can use the db freely while being in separate files than the db open code.
Thanks.
EDIT
I made some progress on solving one of my issues. If you look at tj's blog example he initializes his routes in the app.js like so:
require('./routes/site')(app);
require('./routes/post')(app);
And in the routes js file it starts like this:
module.exports = function(app){
I stumbled on a project earlier today where I saw someone pass 2 variables in the modules.exports call -> function(app, db). Then figured wow could it be that easy, do I need to just adjust my routes to be (app, db) too? Yeah, it seems so.
So now part 1 of the problem is solved. I don't have to require a mongo.js file with the connection boilerplate in every route file. At the same time it's flexible enough where I can decide to pick and choose which route files pass a db reference. This is standard and has no downside right?
Part 2 of the problem (the important one unfortunately) still exists though.
How can I bypass having to do a db.open(...) around every query I make and ideally only make a connection once per session?
Other solution is to pass database to the router via request, like this:
app.js
var db = openDatabase();
var app = express();
app.all('*', function(request, response, next)
{
request.database = db;
next();
});
app.get('/api/user/:id', Users.getByID);
users.js
var Users =
{
getByID: function(request, response)
{
request.database.collection('users').findOne(...)
response.send(user);
}
};
module.exports = Users;
I made a very simple module hub for this case that replaces the use of a global space.
In app.js you can create db connection once:
var hub = require('hub');
hub.db = new Db('foobar', new Server('10.0.2.15', 27017, {}), {native_parser: false});
And use it from any other files:
var hub = require('hub');
// hub.db - here link to db connection
This method uses a feature of 'require'. Module is only loaded for the first time and all the other calls gets a reference to an already loaded instance.
UPDATE
That's what I mean:
In main file like app.js we create Db connection, open it and store into hub:
app.js:
var hub = require('hub');
hub.mongodb = require('mongodb');
hub.mongodbClient = new hub.mongodb.Db('foobar', new hub.mongodb.Server('10.0.2.15', 27017, {}), {native_parser: false});
hub.mongodbClient.open(function(error) {
console.log('opened');
});
Now in any other file (message for example) we have access to opened connection and can simple use it:
message.js:
var hub = require('hub');
var collection = new hub.mongodb.Collection(hub.mongodbClient, 'message');
module.exports.count = function(cb) {
collection.count({}, function(err, count) {
cb(err, count);
});
};
Really silly. In the documentation it seems like db.open requires to be wrapped around whatever is using it, but in reality you can use it without a callback.
So the answer is to just do a db.open() in your database connection module, app.js file or where ever you decide to setup your db server/connection.
As long as you pass a reference to the db in the files using it, you'll have access to an "opened" db connection ready to be queried.