I have a basic Node JS server which is designed to be used as an API, I've created a log and database module and I've started adding other modules to deal with different request types.
I'm using Express.js and node-mysql
When I visit /v1/group I get the following error -
TypeError: Cannot read property 'database' of undefined
at Group.getAll (C:\code\javascript\node\api\api\v1\groups.js:12:23)
at callbacks (C:\code\javascript\node\api\node_modules\express\lib\router\index.js:161:37) ...
So I guess after recieving a request and calling group.getAll() that this is undefined but I don't understand why, is there a way to set this or have I structured my application all wrong?
sever.js
"use strict";
var Express = require('express');
var Log = require('./database/log');
var Database = require('./database/database');
var dbConfig = require('./dbconfig.json');
var Group = require('./api/v1/groups');
//Init express
var app = new Express();
//Init log and database
var log = new Log();
var database = new Database(dbConfig, log);
var initCallback = function() {
//Init routes
var group = new Group(database, log);
//Group routes
app.get('/v1/group', group.getAll);
app.get('/v1/group/:id', group.getByID);
app.listen(3000);
log.logMessage("INFO", "Listening on port 3000");
};
//Test database connection
database.getConnection(function(err, connection) {
if (err) {
log.logMessage("FATAL", "Error connecting to database, check database is running and the dbconfig.json file is present and correct.");
process.exit(1);
}
connection.end();
initCallback();
});
database.js
"use strict";
var mysql = require('mysql');
var Database = function(dbConfig, log) {
this.connected = false;
this.log = log;
this.log.logMessage("INFO", "Connecting to database with: Host - " + dbConfig.dbhost + ", Database port - " + dbConfig.dbport + ", Database name - " + dbConfig.dbname + ", User " + dbConfig.dbuser + ", Password length - " + dbConfig.dbpass.length);
this.pool = mysql.createPool({
host : dbConfig.dbhost,
user : dbConfig.dbuser,
port: dbConfig.dbport,
password : dbConfig.dbpass,
database: dbConfig.dbname
});
};
Database.prototype.getConnection = function() {
var args = arguments;
return this.pool.getConnection.apply(this.pool, arguments);
};
module.exports = Database;
groups.js
"use strict";
var Group = function(database, log) {
this.database = database;
this.log = log;
};
Group.prototype.getAll = function(req, res) {
console.log(this); // --> undefined
var query = 'SELECT * FROM invgroups WHERE published = 1';
this.database.getConnection(function(err, connection) { // --> error line
if (err) { res.send(500, "Database error"); }
connection.query(query, function(err, results) {
if (err) { res.send(500, "Database error"); }
res.send(results);
});
connection.end();
});
};
Group.prototype.getByID = function(req, res) {
console.log(this);
res.send({name: "Group Item 1"});
};
module.exports = Group;
You need to properly bind the function.
app.get('/v1/group', group.getAll);
only passes the getAll function as a handler, but the function itself has no concept of this. this is decided based on the context that is bound, or based on how the function is called. This blog post is useful for understanding how function context works.
app.get('/v1/group', group.getAll.bind(group));
Related
Using NodeJS/ES6 I have created a MongoDB connector class.
class DBClient {
constructor(host, port) {
this.host = host;
this.port = port
this.dbConnection = null;
}
buildConnectionString() {
return 'mongodb://' + this.host + ':' + this.port;
}
connect() {
var connectionString = this.buildConnectionString();
console.log('[MongoDB] - Connecting to instance # ' + connectionString);
var DBConnection = MongoClient.connect(connectionString, function(error, db) {
if (error) {
console.log('[MongoDB] - Error connecting to instance');
console.log(error);
}
else {
console.log('[MongoDB] - Connection Successful');
this.dbConnection = db;
}
});
}
}
Which is then being created in a different file like so
var client = new DBClient('127.0.0.1', '1337');
client.connect();
When the database is connected to, NodeJS crashes when it reaches this.dbConnection = db;, stating TypeError: Cannot set property 'dbConnection' of undefined.
I'm pretty sure it has something to do with being used in a callback, which is screwing up the scope. How can I get around this though? Wouldn't any operation from the callback scope be isolated and unable to reference this?
Also, as a side question, is this a bad code practice to initialize a null property like I'm doing in the constructor? If so, what would be a more proper way of doing it?
Indeed if you want to keep your scope use lambda instead like :
var DBConnection = MongoClient.connect(connectionString, (error, db) =>
{
...
});
if you have to keep your function because of your transpilation settings or the lib does not support lambda, save your scope in a variable like :
var self = this;
var DBConnection = MongoClient.connect(connectionString, function(error, db)
{
... self.dbConnection = db;
});
this is my first time asking questions and this is basically my last resort in finding some answers. Im a noob and beginner in javascript so please use simple terms with me.
So i have an issue. I dont know how to query.
- As in do i put all my queries in one script or do i have to split them up to different scripts.
- Right now, i have a server.js and i put all my codes in there. including queries. So how do i run just one of them.
- and also if there is such a thing for me to query for just another number like 4. Do i have to go back to the script to manually change from '110' to '4' or can i just enter it somewhere.
Some examples are:
//length of 110
db.collection.find({length: "110"}, function(err, collection) {
if( err || !collection) console.log("No collections with 110 in length");
else collection.forEach( function(length) {
console.log(length);
} );
});
//shows record of length 110 and length 340
var length = ['110', '340']
length = length.join('|');
var re = new RegExp(length, 'i')
db.collection.find({length:{$regex: re}}, function(err, collection) {
if( err || !collection ) console.log("User not found");
else collection.forEach (function(length){
console.log(length);
});
});
How do i query to only run for one of them in mongodb. Appericiate the help alot guys
You already know that node.js is used for making servers. So there are 2 ways you can query the database. Since you're new to node, I'm going to list both the ways :
1.A http GET for querying data (Standard Way)
You can write a simple http server and set a route for getting the type of data you want.I've written a small file so that you can understand:
var express = require('express');
var http = require('http');
var app = express();
var bodyParser = require('body-parser');
// Db settings
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'mongodb://localhost:27017/my_database_name';
function getConnection(url, callback) {
MongoClient.connect(url, function(dbErr, dbRes) {
if(dbErr) {
return callback(err, null);
}
callback(null, dbRes);
});
}
// Configure app to use bodyparser
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
var port = process.env.PORT || 7013;
app.set('port', port);
app.use(function(req, res, next) {
console.log(req.ip+ ":"+port + req.url + " "+req.method);
next();
});
app.get('/getCityData', function(req, res, next) {
var cityName = req.query.city;
getConnection(url, function(conErr, db) {
if(conErr) {
return res.send("ERROR IN GETTING connection");
}
var cityCollection = db.collection('cities');
cityCollection.find({"city":cityName}).toArray(function(err, result) {
if(err) return res.send("error in querying data");
db.close();
res.send(result);
});
});
});
var httpServer = http.createServer(app).listen(port, function() {
console.log("Express server listening on port "+app.get('port'));
});
You can query the server using curl or postman like this :
2.Using command line arguments :
You can also do it the easy way using command line arguments by passing the parameter to query, but it's less flexible:
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;
var url = 'mongodb://localhost:27017/my_database_name';
function getConnection(url, callback) {
MongoClient.connect(url, function(dbErr, dbRes) {
if(dbErr) {
return callback(err, null);
}
callback(null, dbRes);
});
}
var cityName = process.argv[2]; // that's the argument you'd receive
getConnection(url, function(conErr, db) {
if(conErr) {
return res.send("ERROR IN GETTING connection");
}
var cityCollection = db.collection('cities');
cityCollection.find({"city":cityName}).toArray(function(err, result) {
if(err) return res.send("error in querying data");
db.close();
console.log(result);
});
});
Pass that commandline argument like this while executing file :
I hope it helps
The code is only displaying the last record from the database. What do I do to get it to display all the records from the database. I'm trying this by using nodeJS. Thank you
var express = require('express');
var mysql = require('mysql');
var app = express();
var data;
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '',
database : 'music'
});
connection.connect();
connection.query('SELECT * FROM artist', function(err, rows, fields) {
if(err) throw err;
data = JSON.stringify(rows);
for(var i=0;i<rows.length;i++)
data = rows[i].artist_name + " "+rows[i].artist_id;
});
connection.end();
app.get("/artists", function(req,res){
res.send(data);
})
var myServer = app.listen(3000, function(){
console.log("Server listening on port 3000");
})
You are assigning your data value to each row in the for loop; that is, every iteration of the loop, you replace the value. Instead of using the assignment operator (=) use a contaminator (+=):
var data = "";
var rowDelimiter = "<br>"; // Or whatever you want
And then:
data += rows[i].artist_name + " "+rows[i].artist_id + rowDelimiter;
I'm very new to node.js and I'm having struggle with querying to MySQL DB. This is a very simple web page, all I have to do is read the value from the input and search it on my DB.
The problem is that var num is still undefined when the web page executes the query. How do I guarantee that I get that value before executing the query?
var http = require("http");
var url = require('url');
var fs = require('fs');
var io = require('socket.io');
var express = require('express');
var mysql = require('mysql');
var port = process.env.PORT || 8001;
var router = express.Router();
var app = express();
var server = http.createServer(app);
var n_eleitor;
var nome;
var local;
var num_bi;
var num;
// ---- ROUTES ------
app.get('/', function(req, res) { //homepage
res.sendFile(__dirname+'/index.html');
handle_database(req, res);
});
app.get('/result', function(req, res, next) { //results
res.render('result.ejs', { n_eleitor: n_eleitor, local: local, nome: nome });
});
app.use('/', router);
// ---- CONECTION -----
server.listen(port);
var listener = io.listen(server);
listener.sockets.on('connection', function(socket){
socket.on('client_data', function(data){ //receive data from client
//console.log(data.letter);
num_bi = data.letter;
console.log(num_bi);
var num = "'"+num_bi+"'";
console.log(num);
});
});
// ---- MYSQL ------
var pool = mysql.createPool ({ //pool maitains a cache of database connections -> handles multiple connections
connectionLimit : 100,
host : 'localhost',
user : 'root',
password : 'soraia',
database : 'pti2',
});
function handle_database(req, res) {
pool.getConnection(function(err, connection){
if(err){
connection.release(); //connection returns to the pool, ready to be used again by someone else.
return;
}
//console.log('ID:' + connection.threadId);
connection.query("select eleitor.*, freguesia.designacao from freguesia, eleitor where num_bi= ? and freguesia.cod_freg=eleitor.cod_freg",[num], function(err, rows, fields){
n_eleitor = rows[0].cod_eleitor;
nome = rows[0].nome;
local = rows[0].designacao;
connection.release();
console.log(num);
console.log(rows);
});
});
}
When I run the program I get "TypeError: Cannot read property 'cod_eleitor' of undefined" and I think that's because what I said before...
Can someone help me, please?
I've been looking for quite a while for a solution but haven't found anything yet.
I'm trying to emit a message from a server every time the server sees that a file has changed in a specified directory. However, instead of only emitting one message, it insists on emitting the same message three times. I am using chokidar to watch the directory, and inside of the 'change' event I emit the message.
Server side code:
var express = require('express')
, app = express()
, http = require('http')
, server = http.Server(app)
, io =require('socket.io')(server)
, chokidar = require('chokidar');
server.listen(1234);
app.use('/public', express.static( __dirname + '/public'));
app.get('/', function(request, response){
var ipAddress = request.socket.remoteAddress;
console.log("New express connection from: " + ipAddress);
response.sendfile(__dirname + '/public/index.html'); //Server client
});
var watcher = chokidar.watch("temp", {ignored: /[\/\\]\./, persistent: true});
watcher.on('change', function(path){
console.log(path + " has changed.");
fs.readFile(path,'utf8', function(err, data){
if(err) {
return console.log(err);
}
else
{
var json = JSON.parse(data), recPsec, type;
recPsec = json.data[0].values[0];
type = json.data[0].values[16];
var compiled = {
"recPsec" : recPsec,
"type" : type
}
var jsonMessage = JSON.stringify(compiled)
io.sockets.emit('message', JSON.stringify(jsonMessage));
console.log("Sent message");
}
});
});
watcher.on('unlink', function(path){
console.log('File: ', path, ' has been removed');
});
watcher.on('add', function(path){
console.log("hi");
fs.readFile(path,'utf8', function(err, data){
if(err) {
return console.log(err);
}
else
{
var json = JSON.parse(data), recPsec, type;
recPsec = json.data[0].values[0];
type = json.data[0].values[16];
var compiled = {
"recPsec" : recPsec,
"type" : type
}
var jsonMessage = compiled;
io.sockets.emit('message', JSON.stringify(jsonMessage));
console.log("message sent");
}
//fs.unlinkSync(path);
});
});
Client Side:
var socket = io.connect('http://localhost');
socket.on('message', function(data){
console.log(data);
var parsed = JSON.parse(data);
recPsecNew = parsed.recPsec;
typeNew = parsed.type;
analyze(recPsecNew, typeNew);
});
I am using socket.io in conjunction with express 4.
Chokidar is found here: https://github.com/paulmillr/chokidar
Logs from the console if I change the name of a file twice are shown here: http://s000.tinyupload.com/?file_id=95726281991906625675
Have you tried lodash's Function?
Probably you can use lodash.debounce function
According to its docs:
_.debounce(func, [wait=0], [options])
Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked. The debounced function comes with a cancel method to cancel delayed invocations. Provide an options object to indicate that func should be invoked on the leading and/or trailing edge of the wait timeout. Subsequent calls to the debounced function return the result of the last func invocation.