I'm currently trying to retrieve data from a sqlite query in node.js, the sql function is on a diferent file so i'm exporting it as a module and then call the function from the index.js. But when i try to retrieve the data the function returns a null value.
Here is my code
Index.js
var express = require("express");
var body_parser = require("body-parser");
var app = express();
var db = require('./dbhandler.js');
app.set("view engine", "jade");
app.get("/data",function(req,res){
let data = db.select();
res.send(data);
});
app.get("/",function(req,res){
res.render("index");
});
app.listen(8888);
dbhandler.js
var sqlite3 = require("sqlite3");
const file = "hr";
exports.select = function (){
var lista = [];
var db = new sqlite3.Database(file);
db.all("SELECT * FROM usuarios", function(err,rows){
let contador = 0;
rows.forEach(function (row) {
lista[contador] = row.nombre + ";" + row.cedula + ";" + row.edad + ";" + row.pais;
});
});
db.close();
return lista;
}
Node is asynchronous!!!. lista is returned from the module before the db.all function completes.
You either need to pass a callback into the select function or return a promise. The callback approach would look something like this:
exports.select = function (cb){
var lista = [];
var db = new sqlite3.Database(file);
db.all("SELECT * FROM usuarios", function(err,rows){
if(err) return cb(err);
let contador = 0;
rows.forEach(function (row) {
lista[contador] = row.nombre + ";" + row.cedula + ";" + row.edad + ";"
+ row.pais; });
db.close();
return cb(null, lists);
});
}
Related
I have the code below, from a REST API, that inserts data in Mysql. I use Node and Express (this is, in fact, my 1st Node project, so please bear in mind I don't understand much about Node).
What I need is that response to client (browser, web application, Postman for testing or whatever access to the API) is returned only when the forEach loop and data insertion into DB terminates, so I get a JSON object with the list error messages, if any.
I've been hitting my head on the wall for half a day, and this is what I got so far.
var wait=require('wait.for');
var async = require('async');
var Promise = require('promise');
var Q = require('q');
var errmsg = [];
router.route('/subscriber').post((req, res, callback) => {
const data = req.body;
var subscriberCollection = data;
this.errmsg = [];
let asyncCall =
(async () => {
let rr = await new Promise (resolve => subscriberCollection.forEach(function (value, key){
var phoneNumber = value.phoneNumber;
var msg = "";
if (phoneNumber == ""){
msg = "ERROR","missing phoneNumber for subscriber index #" + key + ";Skipping";
console.log(msg);
errmsg[key] = msg
return;
}
var sql = "call insertSubscriber(?)";
console.log("INFO",`Inserting subscriber ${phoneNumber} index ${key}`);
connection.query(sql,[ phoneNumber ] ,function (err, data) {
if (err){
var msg = err.errno + " - " + err.sqlMessage;
console.log("ERROR" , msg);
errmsg[key] = msg;
}
});
}) //end forEach
); //end Promise
})();
asyncCall.then(console.log("ENDING!!") ); // THIS IS NOT WORKING
});
On the console, I get this:
INFO Inserting 916311145 for index 0
INFO Inserting 916311146 for index 1
ENDING!!
ERROR 1062 - Duplicate entry '916311145' for key 'phoneNumber_UNIQUE'
ERROR 1062 - Duplicate entry '916311146' for key 'phoneNumber_UNIQUE'
but what I need it to be is:
INFO Inserting 916311145 for index 0
INFO Inserting 916311146 for index 1
ERROR 1062 - Duplicate entry '916311145' for key 'phoneNumber_UNIQUE'
ERROR 1062 - Duplicate entry '916311146' for key 'phoneNumber_UNIQUE'
ENDING!!
Also, when all subscriber objects are saved on DB, I need to return a response to client, something like:
[{"key 0" : "ok"},{"key 1" : "ok"}, {"key 3": "ERROR 1062 - Duplicate entry '916311145' for key 'phoneNumber_UNIQUE'"}...]
and again, the response should only appear when all processing has finished.
How can I get this work?
Hmm try this:
var wait = require('wait.for');
var async = require('async');
var Promise = require('promise');
var Q = require('q');
router.route('/subscriber').post(async (req, res, callback) => {
const data = req.body;
var subscriberCollection = data;
const response = await Promise.all(
subscriberCollection.map(function (value, key) {
var phoneNumber = value.phoneNumber;
var msg = '';
const obj = {};
if (phoneNumber == '') {
msg = 'ERROR missing phoneNumber for subscriber index #' + key + ';Skipping';
console.log(msg);
obj[key] = msg;
Promise.resolve(obj);
return;
}
var sql = 'call insertSubscriber(?)';
console.log('INFO', `Inserting subscriber ${phoneNumber} index ${key}`);
return new Promise((resolve) => {
connection.query(sql, [phoneNumber], function (err, data) {
if (err) {
var msg = 'ERROR' + err.errno + ' - ' + err.sqlMessage;
console.log(msg);
obj[key] = msg;
resolve(obj);
return;
}
obj[key] = 'ok';
resolve(obj);
});
});
}) //end forEach
); //end Promise
console.log('ENDING!!');
res.send(response);
});
I'm trying to write a list of habit objects to a JSON file, but I can't figure it out. I'm doing this because I want to use this JSON file with node.js.
I've created a section with a class called "habits" that I want to fill this JSON file with, the section itself gets the habit objects from this piece of code:
var addHabit = function () {
var $new_habit = {
"name":"",
"value":0,
"goal":0,
"html": null
}
if ($(".habit-input input").val() !== "") {
$new_habit.name = $("#habitinput .name").val();
$new_habit.value = $("#habitinput .value").val();
$new_habit.goal = $("#habitinput .goal").val();
$new_habit.html = $("<p id="+uid+">").html("<span class=\"name\">"+$new_habit.name+"</span> <span class=\"val\">" + $new_habit.value + "</span>/" + "<span class=\"goal\">"+$new_habit.goal + "</span>"+
"<button class=\"plus\">+</button><button class=\"min\">-</button><button class=\"delete\">x</button><button class=\"mod\">modify</button>");
console.log($new_habit);
$(".habits").append($new_habit.html);
$(".habit-input input").val("");
$("#"+uid + " .plus").on("click", function (event) {
var val = parseInt( $(this).parent().find(".val").text());
$(this).parent().find(".val").text( val+1 );
event.preventDefault();
});
$("#"+uid + " .min").on("click", function (event) {
var val = parseInt( $(this).parent().find(".val").text());
$(this).parent().find(".val").text( val-1 );
event.preventDefault();
});
$("#"+uid + " .delete").on("click", function (event) {
$(this).parent().remove();
event.preventDefault();
});
$("#"+uid + " .mod").on("click", function (event) {
var val = parseInt( $(this).parent().find(".val").text());
var name = parseInt( $(this).parent().find(".name").text());
var goal = parseInt( $(this).parent().find(".goal").text());
$(this).parent().find(".val").text(val = $("#habitinput .value").val());
$(this).parent().find(".name").text(name = $("#habitinput .name").val());
$(this).parent().find(".goal").text(goal = $("#habitinput .goal").val());
event.preventDefault();
});
uid++;
};
};
I want to read the section "habits" into the JSON file so I can use it in this node.js file:
var express = require("express");
var url = require("url");
var http = require("http");
var fs = require('fs');
var port = 3000;
var app = express();
app.use(express.static(__dirname + "/client"));
//logger component
app.use(function (req, res, next) {
console.log("[LOG] %s %s", new Date(), req.url);
next();
});
http.createServer(app).listen(port);
//clients requests habits
app.get("/habits", function (req, res) {
console.log("Habits requested!");
res.sendfile('Habit/client/habits.json');
});
What I hope to achieve is that when I go to localhost:3000/habits in my browser that I get all the habit objects in JSON format.
At the moment when I go to localhost:3000/habits I get this {"type":"Buffer","data":[123,13,10,32,32,32,32,34,121,101,121,34,32,58,32,49,50,13,10,125]}
Any help would be greatly appreciated
You're getting a buffer back from the GET/habits. Need to convert it to a something you can read
try calling toString('utf-8')
OR
import bodyParser from 'body-parser';
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
I'm new to nodejs.
Here is my .js file. I'm trying to expose audioData variable to other functions. audioData variable value is being empty outside the function. I see the value when I print inside the function. What could be wrong?
'use strict';
var asyncrequest = require('request');
var xml2js = require('xml2js');
var parseString = xml2js.parseString;
var audioData = [];
asyncrequest("http://example.com/feed", function(error, responsemeta, body) {
parseString(body, function(err, result){
var stories = result['rss']['channel'][0]['item'];
console.log("Total stories: " + stories.length);
stories.forEach(function(entry) {
var singleObj = {}
singleObj['title'] = entry['title'][0];
singleObj['value'] = entry['enclosure'][0].$.url;
audioData.push(singleObj);
});
});
console.dir(audioData);
});
module.exports = audioData;
console.log("Program ended");
You'll have to return a promise for the audioData, not the audioData itself! You can learn more about promises elsewhere. Happily there's a promisified version of request, request-promise, that you can use like so:
'use strict';
var rp = require('request-promise');
var xml2js = require('xml2js');
var parseString = xml2js.parseString;
var audioData = [];
var promiseForAudioData = rp('http://example.com/feed')
.then(body => {
parseString(body, function(err, result){
var stories = result['rss']['channel'][0]['item'];
console.log("Total stories: " + stories.length);
stories.forEach(function(entry) {
var singleObj = {}
singleObj['title'] = entry['title'][0];
singleObj['value'] = entry['enclosure'][0].$.url;
audioData.push(singleObj);
});
});
return audioData;
})
.catch(console.error.bind(console));
module.exports = promiseForAudioData;
console.log("Program ended");
If you don't want to use promises, you can either export inside the callback or export the request method itself.
asyncrequest("http://example.com/feed", function(error, responsemeta, body) {
parseString(body, function(err, result){
var stories = result['rss']['channel'][0]['item'];
console.log("Total stories: " + stories.length);
stories.forEach(function(entry) {
var singleObj = {}
singleObj['title'] = entry['title'][0];
singleObj['value'] = entry['enclosure'][0].$.url; audioData.push(singleObj);
});
module.exports = audioData;
});
});
// Or
exports.get = function (callback) {
return asyncrequest(/* ... */, callback);
}
// Other module
require("./module").get(function (audioData) {
/* Do something */
})
I have just started learning to code about 5 days ago and what I'm struggling to achieve, is to have an rssfeed-to-twitter script that posts a shortened url instead of a full website/article feed url. I found a node.js module called TinyURL that could do that but i struggle to get it to work. Here's the full script:
var simpleTwitter = require('simple-twitter');
var fs = require('fs');
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end('RSS Twitter Bot\n');
}).listen(5693);
var timeInterval = 300000; // run every 30m
var timerVar = setInterval (function () {runBot()}, timeInterval);
function runBot(){
var lastCompleted = Date.parse(new Date(0));
console.log(lastCompleted);
try {
var lastcompletedData = fs.readFileSync('./lastCompleted.json', 'utf8');
var timeData = JSON.parse(lastcompletedData);
var lastCompletedFromFile = Date.parse(new Date(timeData.lastCompleted));
if ( isNaN(lastCompletedFromFile) == false ) {
lastCompleted = lastCompletedFromFile;
}
} catch (e) {
console.log(e);
}
fs.readFile('./config.json', 'utf8', function (err, data) {
if (err) console.log(err); // we'll not consider error handling for now
var configData = JSON.parse(data);
console.log(configData);
var twitter = new simpleTwitter( configData.consumerKey //consumer key from twitter api
, configData.consumerSecret //consumer secret key from twitter api
, configData.accessToken //access token from twitter api
, configData.accessTokenSecret //access token secret from twitter api
, 3600);
var dateNow = Date.parse(new Date());
var FeedParser = require('feedparser');
var request = require('request');
var req = request(configData.feedUrl);
var feedparser = new FeedParser();
req.on('error', function (error) {
console.log(error);
});
req.on('response', function (res){
var stream = this;
if (res.statusCode != 200 ) return this.emit('error', new Error('Bad status code'));
stream.pipe(feedparser);
});
feedparser.on('error', function(error) {
console.log(error);
});
feedparser.on('readable', function() {
var stream = this;
var meta = this.meta;
var item;
while (item = stream.read()) {
var itemDate = Date.parse(item.date);
//check to not publish older articles
if (itemDate > lastCompleted){
var titleLength = item.title.length;
var itemTitle = item.title;
var itemLink = item.link;
if (titleLength > 100) {
itemTitle = itemTitle.substring(0, 100);
}
twitter.post('statuses/update'
, {'status' : itemTitle + ' ' + itemLink + " " + configData.tags}
, function (error, data) {
console.dir(data);
});
console.log(itemTitle + ' ' + item.link + configData.tags);
}
}
//TO KNOW WHEN FROM TO START POSTING
var dateCompleted = new Date();
console.log('loop completed at ' + dateCompleted);
var outputData = {
lastCompleted : dateCompleted
}
var outputFilename = './lastCompleted.json';
fs.writeFile(outputFilename, JSON.stringify(outputData, null, 4), function(err) {
if(err) {
console.log(err);
} else {
console.log("JSON saved to " + outputFilename);
}
});
});
});
}
And this is the TinyURL node.js module
var TinyURL = require('tinyurl');
TinyURL.shorten('http://google.com', function(res) {
console.log(res); //Returns a tinyurl
});
Changing the 'http://google.com' string to itemLink var works just fine and prints it in the terminal as expected.
TinyURL.shorten(itemLink, function(res) {
console.log(res); //Returns a tinyurl
});
What i'm trying to achieve is:
twitter.post('statuses/update', {'status' : itemTitle + ' ' + tinyurlLink + " " + configData.tags}
How can i get the response turned into a e.g var tinyurlLink to replace the itemLink var? Any help would be much appreciated!
As suggested by #zerkms sending a tweet from inside the TinyURL.shorten worked!
So I'm currently trying to make an http status code checker. But for some reason the response hostname is returning undefined, yet i can retrieve the response statusCode. Am I grabbing it properly?
var fs = require('fs');
var http = require('http');
var stdin = process.openStdin();
stdin.addListener('data', function (userInput) {
var urlListPath = userInput.toString().trim();
fs.readFile(urlListPath, function (err, data) {
if (err) {
return console.log(err);
}
var urlArray = data.toString().split("\n");
urlArray = urlArray.filter(Boolean);
for (var i = 0; i < urlArray.length; i++){
http.get({hostname: urlArray[i]}, function(res){
console.log(res.hostname + ' | ' + res.statusCode + ' | ' + res.statusMessage);
});
}
});
});
Solved by wrapping in a function as #bluesman suggested:
var fs = require('fs');
var http = require('http');
var stdin = process.openStdin();
stdin.addListener('data', function (userInput) {
var urlListPath = userInput.toString().trim();
fs.readFile(urlListPath, function (err, data) {
if (err) {
return console.log(err);
}
var urlArray = data.toString().split("\n");
urlArray = urlArray.filter(Boolean);
for (var i = 0; i < urlArray.length; i++){
getHttpInfo(urlArray[i]);
}
});
});
function getHttpInfo(url){
http.get({hostname: url}, function(res){
console.log(url + ' : ' + res.statusCode + ' | ' + res.statusMessage);
});
}