I have created a little application that implemented a JSON file as the data store. I'm trying to learn about MEAN, so I'm trying to convert it to a NODE.js app.
I have created a mongoDB importing my JSON file using mongoimport. The db is there and connected. When I put http://localhost:3000/api/characters into the browser it returns JSON for all the characters.
I have built a connection string and required it into my controller as follows...
// FROM node app characters.controller.js
var dbconn = require('../data/dbconnection.js');
var characterData = require('../data/characters.json');
module.exports.charactersGetAll = function(req, res) {
var db = dbconn.get();
var collection = db.collection('characters');
// Get the documents from the collection
// Need to use to Array() as its only a cursor if you don't
collection
.find()
.toArray(function(err, docs) {
console.log("Found characters!", docs);
res
.status(200)
.json(docs);
});
//console.log('db', db);
//console.log("GET the Characters");
//console.log(req.query);
res
.status(200)
.json(characterData);
};
module.exports.charactersGetOne = function(req, res) {
var charId = req.params.id;
var thisChar = characterData[charId];
console.log("GET characterId", charId);
res
.status(200)
.json(thisChar);
};
From the non-NODE version of the app, I call in the JSON data as follows in my main.js file:
//FROM TRADITIONAL HTML/JS application
// Get JSON and callback so JSON can be stored globally
$.getJSON('people.json', callback);
// Populate faces and names in HTML
function callback(data) {
/*optional stuff to do after success */
var $charNames = $('.char-names');
var $faceImage = $('.faces');
$.each(data, function(index, val) {
console.log("success");
/* iterate through array or object */
/* .eq() method constructs new object from one element from set */
$charNames.eq(index).text(val.name);
$faceImage.eq(index).attr('src', val.image);
//Push all JSON to array
allTheCharacters.push(val);
allTheCharactersComp.push(val);
});
}
What I want to ask is – Is there a simple way I can access the mongoDB in the non-NODE main.js file instead of using the $.getJSON method and how would I add/adapt this for the node characters.controller.js
Hopefully, I am making sense. Apologies in advance for any misunderstanding.
Related
File called testing.js
I can do whatever I like with the data in saveWeatherData but cannot call this function and return the data without getting 'undefined'
For example if i tried the below code in saveWeatherData it will print out the summary as expected...
console.log(The summary of the weather today is: ${dataArray[0]});
However I want to use these values within another file such as a server file that when connected to will display weather summary temperature etc.
So I need to return an array with these values in it so that I can call this function and get my data stored in an array for further use.
I know that the reason the array --dataArray is returning undefined is because asynchronous code.
The array is returned before we have gotten the data using the callback.
My question, is there anyway to do what I am trying to do?
I tried my best to explain the problem and what I want to do, hopefully its understandable.
Would I have to use a callback inside of a callback? To callback here to return the data when its been fetched?
I just cant get my head about it and have tried multiple things to try and get the result I am looking for.
My last idea and something i would prefer not to do is the use the 'fs' module to save the data to a text or json file for use in my other files through reading the data from the saved file...
I feel im close but cant get over the last hurdle, so ive decided to ask for a little help, even just point me on the right track and Ill continue to try and figure it out.
Phew...
Thank you for your time!
const request = require("request");
let dataArray = [];
let saveWeatherData = function(weatherData) {
dataArray = weatherData;
return dataArray;
};
let getWeatherData = function(callback) {
request({
url: `https://api.forecast.io/forecast/someexamplekey/1,-1`,
json: true
}, (error, response, body) => {
//Creating array to hold weather data until we can save it using callback...
let array = [];
if (error) {
console.log("Unable to connect with Dark Sky API servers.")
}
else {
console.log(`Successfully connected to Dark Sky API servers!\n`);
array.push(body.currently.summary, body.currently.temperature, body.currently.apparentTemperature, body.currently.windSpeed, body.currently.windBearing);
callback(array);
}
});
};
getWeatherData(saveWeatherData);
module.exports = {
saveWeatherData
};
My Other File...
File called server.js
const http = require("http");
const testing = require("./testing");
function onRequest(request, response){
let data = testing.saveWeatherData();
console.log(`A user made a request: ${request.url}`);
response.writeHead(200, {"context-type": "text/plain"});
response.write("<!DOCTYPE html>");
response.write("<html>");
response.write("<head>");
response.write("<title>Weather</title>");
response.write("</head>");
response.write("<body>");
response.write("Weather summary for today: " + data[0]);
response.write("</body>");
response.write("</html>");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server is now running on port 8888...");
I'm still not sure about what are you trying to do. However, I think you're not exporting what you suppose to be exporting. To avoid the use of so many callbacks you may use async/await.
Change this part of your server.js
async function onRequest(request, response) {
let data = await testing.getWeatherData();
console.log(`A user made a request: ${request.url}`);
response.writeHead(200, { 'context-type': 'text/plain' });
response.write('<!DOCTYPE html>');
response.write('<html>');
response.write('<head>');
response.write('<title>Weather</title>');
response.write('</head>');
response.write('<body>');
response.write('Weather summary for today: ' + data[0]);
response.write('</body>');
response.write('</html>');
response.end();
}
And this of your testing.
let getWeatherData = function() {
return new Promise(resolve =>
request(
{
url: `https://api.darksky.net/forecast/someexamplekey/1,-1`,
json: true
},
(error, response, body) => {
//Creating array to hold weather data until we can save it using callback...
let array = [];
if (error) {
console.log('Unable to connect with Dark Sky API servers.');
} else {
console.log(`Successfully connected to Dark Sky API servers!\n`);
array.push(
body.currently.summary,
body.currently.temperature,
body.currently.apparentTemperature,
body.currently.windSpeed,
body.currently.windBearing
);
resolve(array);
}
}
)
);
};
module.exports = {
getWeatherData
};
It will check for new Weather in each request. If you want to save the result to avoid checking every single time you might need to do something else. But I think for a weather app the important is to keep it updated.
I'm trying to make a .js file that will constantly have the price of bitcoin updated (every five minutes or so). I've tried tons of different ways to web scrape but they always output with either null or nothing. Here is my latest code, any ideas?
var express = require('express');
var path = require('path');
var request = require('request');
var cheerio = require('cheerio');
var fs = require('fs');
var app = express();
var url = 'https://blockchain.info/charts/';
var port = 9945;
function BTC() {
request(url, function (err, res, body) {
var $ = cheerio.load(body);
var a = $(".market-price");
var b = a.text();
console.log(b);
})
setInterval(BTC, 300000)
}
BTC();
app.listen(port);
console.log('server is running on '+port);
It successfully says what port it's running on, that's not the problem. This example (when outputting) just makes a line break every time the function happens.
UPDATE:
I changed the new code I got from Wartoshika and it stopped working, but im not sure why. Here it is:
function BTCPrice() {
request('https://blockchain.info/de/ticker', (error, response, body) => {
const data = JSON.parse(body);
var value = (parseInt(data.USD.buy, 10) + parseInt(data.USD.sell, 10)) / 2;
return value;
});
};
console.log(BTCPrice());
If I have it console.log directly from inside the function it works, but when I have it console.log the output of the function it outputs undefined. Any ideas?
I would rather use a JSON api to get the current bitcoin value instead of an HTML parser. With the JSON api you get a strait forward result set that is parsable by your browser.
Checkout Exchange Rates API
Url will look like https://blockchain.info/de/ticker
Working script:
const request = require('request');
function BTC() {
// send a request to blockchain
request('https://blockchain.info/de/ticker', (error, response, body) => {
// parse the json answer and get the current bitcoin value
const data = JSON.parse(body);
value = (parseInt(data.THB.buy, 10) + parseInt(data.THB.sell, 10)) / 2;
console.log(value);
});
}
BTC();
Using the value as callback:
const request = require('request');
function BTC() {
return new Promise((resolve) => {
// send a request to blockchain
request('https://blockchain.info/de/ticker', (error, response, body) => {
// parse the json answer and get the current bitcoin value
const data = JSON.parse(body);
value = (parseInt(data.THB.buy, 10) + parseInt(data.THB.sell, 10)) / 2;
resolve(value);
});
});
}
BTC().then(val => console.log(val));
As the other answer stated, you should really use an API. You should also think about what type of price you want to request. If you just want a sort of index price that aggregates prices from multiple exchanges, use something like the CoinGecko API. Also if you need real-time data you need a websocket-based API, not a REST API.
If you need prices for a particular exchange, for example you're building a trading bot for one or more exchanges, you;ll need to communicate with each exchange's websoceket API directly. For that I would recommend something like the Coygo API, a node.js package that connects you directly to each exchange's real-time data feeds. You want something that doesn't add a middleman since that would add latency to your data.
I am currently trying to return a request of all the file names (in each existing folder) on a particular website. My web application is using NodeJS, Express, Cheerio, and Request to web scrape. My code is first getting a list of all the folder names. After retrieving a list of folder names, it then goes inside each folder name to get a list of file names and store them in the 'files' array. Finally, the 'files' array is what will be sent to the client-side.
Right now I am having a big issue with asynchronous stuff because my request would always return an empty list of 'files'. I have the Q node module installed and have tried using promises, but have had no luck getting the results I want. I am still new to nodeJS and would love it if someone can help me out.. :)
exports.getAllImages = function(req, res) {
var folders = [];
var files = [];
//Step 1: Get folder names and store all of them in the 'folders' array
var foldersUrl = 'http://students.washington.edu/jmzhwng/Images/';
request(foldersUrl, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
$("a:contains('-')").filter(function(){
var data = $(this)[0].attribs.href;
folders.push(data);
})
//Step 2: Using the 'folders' array, get file names in each folder and store all of them in the 'files' array
for (var i=0; i < folders.length; i++) {
var imagesUrl = 'http://students.washington.edu/jmzhwng/Images/' + folders[i];
request(imagesUrl, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
$("a:contains('.')").filter(function(){
var data = $(this)[0].attribs.href;
files.push(data);
})
}
})
}
//Step 3: Return all file names to client-side
res.json({
images: files
}, 200);
console.log('GET ALL IMAGES - ' + JSON.stringify(files));
}
})
For better readability or support, you can view the JSFiddle I created here: http://jsfiddle.net/fKGrm/
You don’t necessarily need promises for this—you’re 95% of the way there already without them. The main issue, as I think you’re aware, is that your response is being sent before the image requests come back. You just need to wait for those to finish before you send the response.
The most basic way is to count the number of callbacks you receive in your Step 2. When it equals the folders.length, then send your response.
Here’s a simplified version of that:
var request = require('request'),
cheerio = require('cheerio');
var baseUrl = 'http://students.washington.edu/jmzhwng/Images/';
var files = [];
request(baseUrl, function (error, res, body) {
var folders = folderLinks(cheerio.load(body));
count = 0;
folders.forEach(function (folder) {
request(baseUrl + folder, function (error, res, body) {
files.push.apply(files, fileLinks(cheerio.load(body)));
if (++count == folders.length) {
console.log(files);
}
});
});
});
function folderLinks ($) {
return $('a:contains(-)').get().map(function (a) {
return a.attribs.href;
});
}
function fileLinks ($) {
return $('a:contains(.)').get().map(function (a) {
return a.attribs.href;
});
}
I'm currently trying to create a NodeJS server or something similar to mockup a REST API that reads in a JSON file and responds to requests with that data. I really only need GET requests supported. What is the best way to go about this?
Here's what I have so far:
/**
* Sample items REST API
*/
function ItemsRepository() {
this.items = [];
}
ItemsRepository.prototype.find = function (id) {
var item = this.items.filter(function(item) {
return item.itemId == id;
})[0];
if (null == item) {
throw new Error('item not found');
}
return item;
}
/**
* Retrieve all items
* items: array of items
*/
ItemsRepository.prototype.findAll = function () {
return this.items;
}
/**
* API
*/
var express = require('express');
var app = express();
var itemRepository = new ItemsRepository();
app.configure(function () {
// used to parse JSON object given in the body request
app.use(express.bodyParser());
});
/**
* HTTP GET /items
* items: the list of items in JSON format
*/
app.get('/items', function (request, response) {
response.json({items: itemRepository.findAll()});
});
/**
* HTTP GET /items/:id
* Param: :id is the unique identifier of the item you want to retrieve
* items: the item with the specified :id in a JSON format
* Error: 404 HTTP code if the item doesn't exists
*/
app.get('/items/:id', function (request, response) {
var itemId = request.params.id;
try {
response.json(itemRepository.find(itemId));
} catch (exception) {
response.send(404);
}
});
app.listen(8080); //to port on which the express server listen
I know that I would use the following to include the file, I just don't know how to stuff the data into Items.
var responseItemsData = require('./items-list.json');
This is trivial in node. You can load the data by requiring the .json file directly
var responseData = require('./my-json-file'); //.json extension optional
//Do this during your startup code, not during the request handler
Then to send it:
res.write(JSON.stringify(responseData));
The rest of the code you need is easily available in almost every node.js tutorial on the web.
You can use jasmine+sinon:
var Episode = Backbone.Model.extend({
url: function() {
return "/episode/" + this.id;
}
});
beforeEach(function() {
this.server = sinon.fakeServer.create();
});
afterEach(function() {
this.server.restore();
});
it("should fire the change event", function() {
var callback = sinon.spy();
this.server.respondWith("GET", "/episode/123",
[200, {"Content-Type": "application/json"},'{"id":123,"title":"Hollywood - Part 2"}']);
var episode = new Episode({id: 123});
// Bind to the change event on the model
episode.bind('change', callback);
// makes an ajax request to the server
episode.fetch();
// Fake server responds to the request
this.server.respond();
// Expect that the spy was called with the new model
expect(callback.called).toBeTruthy();
expect(callback.getCall(0).args[0].attributes)
.toEqual({id: 123,
title: "Hollywood - Part 2"});
});
more details in: https://github.com/cld-santos/simplologia/tree/master/javascript-lessons/src/test/javascript/Sinon
The easiest way is to simply use the static middleware.
var express = require('express');
var app = express();
app.use('/api', express.static(__dirname + '/data'));
app.use('.*', express.static(__dirname + '/assets'));
This assumes that you are eventually going to put the REST api at /api but that while you're testing your data is going to be in the data directory and that your CSS/JS/HTML is in the assets folder. In reality you can put it whereever you want, but you now can put all your dev json separate from your code.
I created a tool for this purpose
https://github.com/homerquan/kakuen
I'd like to create a model to handle everything related to users, starting with a findOne() function.
app.js:
var u = new User(client);
u.findOne(function(error, user) {
console.log(error, user);
});
models/User.js:
var User = function (client) {
this.client = client
};
User.prototype.findOne = function (id, callback) {
client.connect();
client.get('testkey', function(error, result) {
var test = "hello#world.com";
callback(null, test);
client.close();
});
};
module.exports = User;
node.js complains findOne() would be undefined.
What's the correct way of creating such models and providing them with objects, like database pools etc.?
Your code contains various errors:
You do not use new when creating the instance
You mixed a function with the object literal syntax:
var User = function (client) {
client: client
};
You want this.client = client; instead. Right now the function body does nothing as it just defines a label called client does nothing with the variable client.
I would suggest you to search for an existing ORM for node.js instead of trying to write one on your own.