Node.js variable use outside of function - javascript

I'm trying to make it so that I can pass my trends variable from its function into a renderer for my Pug template, and I can't seem to do it.
var express = require('express');
var router = express.Router();
var googleTrends = require('google-trends-api');
var auth = require('http-auth');
var ustrends;
var uktrends;
const Console = require('console').Console;
var basic = auth.basic({
realm: "Web."
}, function (username, password, callback) { // Custom authentication method.
callback(username === "user" && password === "pass");
}
);
var find = ',';
var regex = new RegExp(find, 'g');
googleTrends.hotTrends('US').then(function(trends){
ustrends = trends
});
googleTrends.hotTrends('EU').then(function(trends1) {
uktrends = trends1
});
console.log(ustrends);
/* GET home page. */
router.get('/', auth.connect(basic), function(req, res, next) {
res.render('index', {trends: ustrends.toString().replace(regex, ", "), trends1: uktrends.toString().replace(regex, ", "), title: 'Trends in the U.S & U.K'});
});
module.exports = router;
As you can see, I'm trying to pass the "ustrends" and "uktrends" variables into the renderer. Any help is appreciated.

Remember that hotTrends will return a promise, as it's getting results from Google's API. Since the renderer is outside of the callbacks wherein ustrends and uktrends are set to values, there's no guarantee these values will be set prior to the renderer being called.
You could use several nested callbacks, but that would lead to some code pushed pretty far to the right; I recommend the async library, which has a function called series that allows you to pass in 1) an array of functions to be executed in order and 2) a callback that will be executed after the functions have completed that takes an error if there was one and the result of the functions as an argument. In the snippet below, the trends API returns results prior to the renderer being called:
async.series([
function(cb) {
googleTrends.hotTrends('US').then(function(trends){
ustrends = trends;
cb();
})
},
function(cb) {
googleTrends.hotTrends('EU').then(function(trends1) {
uktrends = trends1;
cb();
});
}
], function(err, results) {
/* handle errors, do rendering stuff */
})

Related

(Javascript Node.js) How to get varibles from a IIFE

Please see my code below:
I am trying to assign the recordset to a variable, can use index.js to call this variable out.
I am able to console.log the recordset. But when I call this IIFE, it is always says undefined.
var mssql = require('mssql');
var dbcon = require('./dbcon');
var storage = (function () {
var connection = new mssql.Connection(dbcon);
var request = new mssql.Request(connection);
connection.connect(function (recordset) {
request.query('select getdate()', function (err, recordset) {
console.dir(recordset);
});
connection.close();
});
})();
module.exports = storage;
index.js
var storage = require('./storage');
"AMAZON.HelpIntent": function (intent, session, response) {
storage(function (recordset){
var speechOutput = 'Your result is '+recordset;
response.ask(speechOutput);
});
However, I can't get the recordset. I got "Your result is {object, object}. "
that's because the IIFE is executing right away, try returning a function instead and then executing that function when you import that module,
var storage = (function(mssql, dbcon) {
return function() {
var connection = new mssql.Connection(dbcon);
var request = new mssql.Request(connection);
connection.connect(function(recordset) {
request.query('select getdate()', function(err, recordset) {
console.dir(recordset);
});
connection.close();
});
}
})(mssql, dbcon);
and I don't understand why you need the IIFE, why don't you just assign the function to the variable?
If you're trying to assign the variable "recordset" to "storage" then this will never work as "connection.connect" is an asynchronous function, and in that case you should think about callback functions or promises.
Update
Based on your request, here's an implementation with a callback function and how it's used
var mssql = require('mssql');
var dbcon = require('./dbcon');
var storage = function(callback) {
var connection = new mssql.Connection(dbcon);
var request = new mssql.Request(connection);
connection.connect(function(recordset) {
request.query('select getdate()', function(err, recordset) {
if(!err && callback){
callback(recordset);
}
connection.close();
});
});
}
module.exports = storage;
// --------------------------------------------------
// implementation in another module
var storage = require("module_path"); // (1)
var answer;
storage(function(recordset){ // (2)
answer = recordset;
console.log(answer); // actual data, (3)
// implement your logic here
});
console.log(answer); // undefined (4)
// --------------------------------------------------
How this code works:
- You start by calling the storage method and sending it a callback method.
- The whole point of the callback function is that you won't wait for the result, your code will actually continue working at the same time that the storage method is connecting to the database and trying to get the data, ans since db operations are much slower, line(4) will execute before line(3).
- The flow of work will be as follows:
line (1)
line (2)
line (4)
line (3) at sometime in the future when the data is retrieved from database
- To see this more clearly, try doing this at the last line,
setTimeout(function(){console.log(answer);}, 3000);
This will wait for sometime until the data comes back;

Returning queries from couchdb using nano

i've written a simple module to handle my couchdb CRUD operations using nano, however i'm having hardship returning from the results i query from the couch database. My Code is as follows.
couchdb.js
//Select from couch view
exports.couchSelect=function (_db, document,view) {
return _db.view(document, view,function(err, body){
if(!err){
var rows = body.rows; //the rows returned
console.log(rows);
return rows;
}else{
console.log(err);
}
}
);
}
routes.js
var couchdb = require('./couchdb');
app.get("/orders", function (req, res) {
var db = couchdb.couchConnect('ezyextension_orders');
var insert = couchdb.couchSelect(db, 'orders', 'orders');
console.log(insert);
});
On executing the returned output is only get Node http request parameters without the returned rows, need help to return the actual JSON rows queried.Thanx
You're using nano which use callback to make async calls. Returning _db.view only return a void function. I added comments to tell you what is happening :
exports.couchSelect = function(_db, document, view) {
_db.view(document, view, function(err, body) {
//This will be called after the couchSelect request.
if (!err)
console.log("Callback : " + body.rows);
});
}
//When you use it
var couchdb = require('./couchdb');
app.get("/orders", function(req, res) {
var db = couchdb.couchConnect('ezyextension_orders');
var insert = couchdb.couchSelect(db, 'orders', 'orders');
//This is synchronous. This will be called before the callback is called.
console.log(insert);
});
I decided to use blue-nano which uses promises instead of callbacks and the code is as below.
couchdb.js
var nano = require('nano-blue')('http://localhost:5984');
//Select from couch view
exports.couchSelect=function (_db, document,view) {
return _db.view(document, view);
}
routes.js
app.get("/orders", function (req, res) {
var db = couchdb.couchConnect('ezyextension_orders');
couchdb.couchSelect(db, 'orders', 'all').spread(function (body,header) {
res.send(body.rows);
}).catch(function(err) {
console.log(err.message);
});
});
This works perfectly

handling multi clients in node.js api

Couldn't find an answer, so I'm asking here -
I'm writing an API in node.js (6.2.0) and I have a problem when I'm serving to multiple clients.
The code is -
"use strict";
const express = require('express');
const router = express.Router();
const FileRetriever = require('./FileRetriever');
function doSomething(uid, callback) {
let finalCount = 0;
let cb = null;
FileRetriever.foo(uid, function (err, data) {
finalCount = data.length;
cb = callback(finalCount);
data.forEach(function(obj, i) {
doSomething2(obj, cb);
});
})
}
function doSomething2(_obj, cb) {
let fn = null;
FileRetriever.bar(_obj, function(err, data){
cb(null, data);
})
}
router.route('/foo').get(function (req, res) {
let uid = req.query.uid;
function callback(_finalCount) {
let counter = 1;
let finalCount = _finalCount;
let output = [];
return function(err, data) {
output.push(data);
if (output.length === (finalCount -1)) {
res.send(output);
}
}
}
doSomething(uid, callback);
});
Obviously it's a bit more complicated than that, but this is the simplified version.
Please help me understand what am I missing -
This is what I have in mind on how it should work -
A user goes to /foo with a parameter uid.
He gets to this route and doSomething is invoked for this user.
In doSomething, I first get initial data that I invoke callback with that returns a function of its own which will be now known as cb.
When cb is passed to doSomething2 and get invoked there, it's still under the same stack, under the same user.
I ran a couple of tests, with one user that should return an output with the length of 6 and another with the length of 100.
When I run this code once per user, it all works fine, but if the route gets called at the same time by the two users, the lengths are not [6,100] (but they are always the same).
What am I doing wrong?
It should work...
Hope that I was clear, thanks.

Get JSON from javascript file and display in route file using NodeJS

I am using Nodejs Express. I currently have a script that produces an array of objects from Google API. I need to take that JSON data and use it in my templates. How can I call the function in my script from my route file?
This is my script file:
var Spreadsheet = require('edit-google-spreadsheet');
Spreadsheet.load({
debug: true,
spreadsheetId: '1eWmSV4Eq-se4gZSvBfW-J-lEOLwNopEfMavZByJ-qD8',
worksheetId: 'owrromd',
// 1. Username and Password
username: 'user',
password: 'pass',
}, function sheetReady(err, spreadsheet) {
//use speadsheet!
spreadsheet.receive(function(err, rows, info) {
if (err) throw err;
var announcementArray = [];
//console.log(rows);
for (x in rows) {
var eachObject = rows[x]
var side = eachObject['1'];
//console.log(side);
var type = eachObject['2'];
//console.log(type);
var announcement = eachObject['3'];
//console.log(announcement);
var announcementItem = {};
announcementItem.side = side;
announcementItem.type = type;
announcementItem.announcement = announcement;
announcementArray.push(announcementItem);
}
announcementArray.shift();
console.log(announcementArray);
});
});
This is my route js file:
module.exports=function(app){
app.get('/', function(req,res){
res.render('index', {title:"Home page", description:"The is the description"});
});
}
Change the content of the script file, let's call it loadSheet.js
var Spreadsheet = require('edit-google-spreadsheet');
function loadSheet() {
Spreadsheet.load({
debug: true,
spreadsheetId: '1eWmSV4Eq-se4gZSvBfW-J-lEOLwNopEfMavZByJ-qD8',
worksheetId: 'owrromd',
// 1. Username and Password
username: 'user',
password: 'pass',
}, function sheetReady(err, spreadsheet) {
//use speadsheet!
spreadsheet.receive(function(err, rows, info) {
if (err) throw err;
var announcementArray = [];
//console.log(rows);
for (x in rows) {
var eachObject = rows[x]
var side = eachObject['1'];
//console.log(side);
var type = eachObject['2'];
//console.log(type);
var announcement = eachObject['3'];
//console.log(announcement);
var announcementItem = {};
announcementItem.side = side;
announcementItem.type = type;
announcementItem.announcement = announcement;
announcementArray.push(announcementItem);
}
announcementArray.shift();
console.log(announcementArray);
});
});
}
//Export it to module
exports.loadSheet = loadSheet;
Then in the route js:
var ls = require('./loadSheet.js'); //Load the module, get the name of the script file
app.get('/', function(req,res){
res.render('index', {title:"Home page", description:"The is the description"});
ls.loadSheet();
});
So you'd adapt the module the other response created. But you are going to need to give a callback to loadSheet. I am cutting out the main body of that function for clarity.
var Spreadsheet = require('edit-google-spreadsheet');
function loadSheet(theCallback) { //take a callback here.
Spreadsheet.load({...yourdata...}, function sheetReady(...) {
// create your announcementArray
// then call the callback
theCallBack(undefined,announcementArray);
});
});
}
//Export it to module
exports.loadSheet = loadSheet;
Then, from your routes, you can get it like so:
var ls = require('./loadsheet.js'); // assumes in same dir as routes
app.get('/', function(req,res){
ls.loadSheet(function(err,result){
res.render('myTemplate',result);
});
});
I am going to assume you can take care of getting the result data into your template. You can look in the index template to see how it pulls in the data. I don't know whether you are using Jade or EJS.
Note, this is all sort of hackish but addresses your functional question. Let me know if you need a little further direction.

JS - passing a connection(object) from one function to another

I am new to JS and I have a simple question. I am writing a node_redis code to connect to the db.
I have created a db module in which there is an init function to start the connection.
the module also has another function which queries the db. for the query, i will need the connection (dbConnection) object from the first function and then use it in the 2nd function. how do i do this? I can get it done by using global variables but most places tell me its a bad idea.
Sorry if the question is stupid, I am learning how to code. results in google tell me that it can be done by passing it as an object property. But i don't know if it is the proper way to do things in my context, or even how to do it.
var redis = require('redis');
module.exports = redisDb = {
// Initialize the module. Invokes callback when ready (or on error)
init: function(config, callback) {
// Open the database connection
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Connected!");
console.log(dbConnection.keys('*'));
});
dbConnection.on('connect' , log('connect'));
dbConnection.on('ready' , log('ready'));
dbConnection.on('reconnecting', log('reconnecting'));
dbConnection.on('error' , log('error'));
dbConnection.on('idle' , log('idle...'));
dbConnection.on('end' , log('end'));
function log(type) {
return function() {
console.log(type, arguments);
}
}
callback("callback - Connected");
},
getValue: function(key, callback) {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
};
EDIT:
tried another way. still failing.
module.exports = redisDb = (function() {
var config = require('../config');
var redis = require('redis');
return {
connection: function(config) {
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
return dbConnection
},
getValue: function(connection, callback) {
connection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
}
})();
Now one way is as you said to make dbConnection an object Property.
The other way is to call init() in getValue() which results in establishing different connection every time you want some value.
Because a DB Connection is a valuable resource, I'd say it's better to use the second variant.
Of course then you'll need to return dbConnection from init().
PS: Global variables were made initially for such things and then people saw that fewer they are the better. That's why using global vars is considered a bad style.
I made the code work by simply declaring the connection in the parent function.
module.exports = _redisDb = (function() {
var redis = require('redis');
var config = require('../config');
var dbConnection = redis.createClient(config.db.port, config.db.host, {no_ready_check: true});
dbConnection.auth(config.db.authKey, function() {
console.log("Authenticated!");
});
var getValue = function() {
dbConnection.hgetall("hosts", function (err, obj) {
console.dir(obj);
});
}
return {
getValue: getValue
}
})();
While the above work,s I'd still like for someone to tell me how can I pass variables/objects between functions off the same module.

Categories