Connecting Alexa skill to mysql database using node.js and aws lambda - mysql

I am trying to connect my Alexa skill to an Amazon RDS mySQL database using node.js in AWS Lambda. I tested the connection before uploading it to lambda and it worked but when I upload it I get a 'process exited before completing request' or a 'There was a problem with the skills response' error.
'use strict';
const Alexa = require('alexa-sdk');
const APP_ID = 'amzn1.ask.skill.11069fc0-53bc-4cd0-8961-dd41e2d812f8';
var testSQL = 'SELECT weight, height from users where pin=1100';
//=========================================================================================================================================
//Database connection settings
//=========================================================================================================================================
var mysql = require('mysql');
var config = require('./config.json');
// Add connection details for dB
var pool = mysql.createPool({
host : config.dbhost,
user : config.dbuser,
password : config.dbpassword,
database : config.dbname
});
// var dbHeight, dbWeight, dbMuscle, dbExerciseOne, dbExerciseTwo, dbExerciseThree, dbExerciseFour;
var dbResult;
function searchDB(quest) {
pool.getConnection(function(err, connection) {
// Use the connection
console.log(quest);
connection.query(quest, function (error, results, fields) {
// And done with the connection.
connection.release();
// Handle error after the release.
if (!!error) {
console.log('error')
}
else {
console.log(results[0]);
dbResult = results[0];
return dbResult;
console.log(dbResult.height);
}
process.exit();
});
});
};
//searchDB(testSQL);
//=========================================================================================================================================
//TODO: The items below this comment need your attention.
//=========================================================================================================================================
const SKILL_NAME = 'My Application';
const GET_FACT_MESSAGE = "Here's your fact: ";
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
var name, pinNumber;
//=========================================================================================================================================
//Editing anything below this line might break your skill.
//=========================================================================================================================================
const handlers = {
'LaunchRequest': function () {
if(Object.keys(this.attributes).length === 0){
this.attributes.userInfo = {
'userName': '',
'pinNo': 0
}
this.emit('GetPinIntent');
}
else{
name = this.attributes.userInfo.userName;
pinNumber = this.attributes.userInfo.pinNo;
var sql = "";
//var result = searchDB(sql);
//var uWeight = result.weight;
//var uHeight = result.height;
var speechOutput = 'Welcome ' + name + 'Please select an option: Check My BMI, Create Exercise Plan, Create Meal Plan, Update Height and Weight, Update workout status?';
this.emit(':ask', speechOutput);
}
},
'GetPinIntent': function (){
this.emit(':ask','Welcome to my Application, as this is your first time please say your name followed by your pin. For example, my name is Jason and my pin is zero one zero one');
//this.emit(':responseReady');
},
'RememberNameID': function (){
var filledSlots = delegateSlotCollection.call(this);
this.attributes.userInfo.userName = this.event.request.intent.slots.name.value;
this.attributes.userInfo.pinNo = this.event.request.intent.slots.pin.value;
var speechOutput = 'Welcome ' + this.attributes.userInfo.userName + ' we have stored your Pin Number and we will call you by name next time. Please select an option: BMI or exercise';
this.response.speak(speechOutput);
this.emit(':responseReady');
},
'CheckBMI': function(){
var sql = 'SELECT height, weight FROM users WHERE pin=' + this.attributes.userInfo.pinNo;
var heightWeight = searchDB(sql);
dbHeight = parseInt(heightWeight.height);
dbWeight = parseInt(heightWeight.weight);
var speechOutput = bmiCalculator(dbHeight, dbWeight);
this.emit(':ask', speechOutput);
},
'AMAZON.HelpIntent': function () {
const speechOutput = HELP_MESSAGE;
const reprompt = HELP_REPROMPT;
this.response.speak(speechOutput).listen(reprompt);
this.emit(':responseReady');
},
'AMAZON.CancelIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'AMAZON.StopIntent': function () {
this.response.speak(STOP_MESSAGE);
this.emit(':responseReady');
},
'SessionEndedRequest': function() {
console.log('session ended!');
this.emit(':saveState', true);
}
};
exports.handler = function (event, context, callback) {
var alexa = Alexa.handler(event, context, callback);
alexa.APP_ID = APP_ID;
alexa.dynamoDBTableName = 'fitnessDB';
alexa.registerHandlers(handlers);
alexa.execute();
};
function delegateSlotCollection(){
console.log("in delegateSlotCollection");
console.log("current dialogState: "+this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
console.log("in Beginning");
var updatedIntent=this.event.request.intent;
//optionally pre-fill slots: update the intent object with slot values for which
//you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property
this.emit(":delegate", updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
// return a Dialog.Delegate directive with no updatedIntent property.
this.emit(":delegate");
} else {
console.log("in completed");
console.log("returning: "+ JSON.stringify(this.event.request.intent));
// Dialog is now complete and all required slots should be filled,
// so call your normal intent handler.
return this.event.request.intent;
}
};
function bmiCalculator (userHeight, userWeight ) {
var speechOutput = " ";
var h = userHeight/100;
var calcBMI = 0;
calcBMI = userWeight / (h*h);
calcBMI = calcBMI.toFixed(2);
if (calcBMI < 18.5) {
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of " + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently underweight.";
speechOutput += " I would advise you to increase your calorie intake, whilst remaining active.";
return speechOutput;
}
else if (calcBMI >=18.5 && calcBMI < 25){
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently at a normal weight.";
speechOutput += " I would advise you to stay as you are but ensure you keep a healthy diet and lifestyle to avoid falling above or below this.";
this.response.speak(speechOutput);
return speechOutput;
}
else if (calcBMI >=25 && calcBMI < 29.9){
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently overweight.";
speechOutput += " I would advise you to exercise more to fall below this range. A healthy BMI is ranged between 18.5 and 24.9";
this.response.speak(speechOutput);
return speechOutput;
}
else{
speechOutput += "Based on your weight of " +weight+ " kilograms and your height of" + height + " metres, your BMI is " +calcBMI+ ". Meaning you are currently obese.";
speechOutput += " I would advise you to reduce your calorie intake, eat more healthy and exercise more. A healthy BMI is ranged between 18.5 and 24.9";
return speechOutput;
}
};
The code outlines my database connection. I created the connection query as a function as I will need to make varying queries to the database based on the context. Is there a way to create a function within the exports.handler function that will only call the query when needed?
Or are there any other solutions with regards to connecting to the database in such a way.

You are running into multiple issues, without using a Promise or await, your call is running async and you will never get an answer immediately from the RDS for the lambda call. you need to create a function that will wait for an answer before continuing its logic.
The other issue you will run into is the MySQL RDS instance is it running constantly there may be a cold start issue.
The last thing is in the AWS lambda console be sure to allocate enough resources in compute and time to run this function the default 128 mb of memory and the time to run the function can be adjusted to improve performance

Use sync-mysql to make synchronous queries to a mysql database. It worked for me.

Related

How to make a user on my website ping a specific ip address?

I'm wondering how website like this one : https://ping.eu/ping/ manage to make our ip ping an other ip and get the result.
Someone have an idea ?
Thanks
It Doesn't. A PHP script(on the server) will most likely do it with "PHP Sockets". Have a look at
this: https://www.php.net/manual/en/sockets.examples.php
Else it could use exec() function, but that would be a security flaw.
So to answer your question: The website will ping the IP address not the 'client'
If you want to ping a server, i.e. an actual web address/URL like www.google.com, you can look at this JSFiddle http://jsfiddle.net/GSSCD/203/ or GitHub repository https://github.com/jdfreder/pingjs.
Here's some code from the JSFiddle:
function Pinger_ping(ip, callback) {
if(!this.inUse) {
this.inUse = true;
this.callback = callback
this.ip = ip;
var _that = this;
this.img = new Image();
this.img.onload = function() {_that.good();};
this.img.onerror = function() {_that.good();};
this.start = new Date().getTime();
this.img.src = "http://" + ip;
this.timer = setTimeout(function() { _that.bad();}, 1500);
}
}
Another way to ping a server/web address is to use JavaScript and the XMLHttpRequest() function it supports:
HTML:
<div id="result"></div>
JavaScript:
function http_ping(fqdn) {
var NB_ITERATIONS = 4; // number of loop iterations
var MAX_ITERATIONS = 5; // beware: the number of simultaneous XMLHttpRequest is limited by the browser!
var TIME_PERIOD = 1000; // 1000 ms between each ping
var i = 0;
var over_flag = 0;
var time_cumul = 0;
var REQUEST_TIMEOUT = 9000;
var TIMEOUT_ERROR = 0;
document.getElementById('result').innerHTML = "HTTP ping for " + fqdn + "</br>";
var ping_loop = setInterval(function() {
// let's change non-existent URL each time to avoid possible side effect with web proxy-cache software on the line
url = "http://" + fqdn + "/a30Fkezt_77" + Math.random().toString(36).substring(7);
if (i < MAX_ITERATIONS) {
var ping = new XMLHttpRequest();
i++;
ping.seq = i;
over_flag++;
ping.date1 = Date.now();
ping.timeout = REQUEST_TIMEOUT; // it could happen that the request takes a very long time
ping.onreadystatechange = function() { // the request has returned something, let's log it (starting after the first one)
if (ping.readyState == 4 && TIMEOUT_ERROR == 0) {
over_flag--;
if (ping.seq > 1) {
delta_time = Date.now() - ping.date1;
time_cumul += delta_time;
document.getElementById('result').innerHTML += "</br>http_seq=" + (ping.seq-1) + " time=" + delta_time + " ms</br>";
}
}
}
ping.ontimeout = function() {
TIMEOUT_ERROR = 1;
}
ping.open("GET", url, true);
ping.send();
}
if ((i > NB_ITERATIONS) && (over_flag < 1)) { // all requests are passed and have returned
clearInterval(ping_loop);
var avg_time = Math.round(time_cumul / (i - 1));
document.getElementById('result').innerHTML += "</br> Average ping latency on " + (i-1) + " iterations: " + avg_time + "ms </br>";
}
if (TIMEOUT_ERROR == 1) { // timeout: data cannot be accurate
clearInterval(ping_loop);
document.getElementById('result').innerHTML += "<br/> THERE WAS A TIMEOUT ERROR <br/>";
return;
}
}, TIME_PERIOD);
}
But, of course, these are web addresses, not IP addresses, so I'm not sure if that's what you're aiming for. I'm also not sure if you're looking for the amount of time spent to get the connection and the number of packets and bytes sent and received, or if you just want to validate the connection. The above code does all of those things. For IP addresses, you can try an AJAX request to ping a server, which only sees if there is a connection using YOUR SERVER'S IP address, NOT THE USER'S CLIENT, like this:
client --AJAX-- yourserver --ICMP ping-- targetservers
You could also try:
Using a Java applet with isReachable
Writing a server-side script which pings, and using AJAX to communicate to your server-side script
You might also be able to ping in Flash (using ActionScript)
One last hypothetical and unorthodox way to get an IP address is to inspect and view the source of the website you mentioned and copy some code, mostly JavaScript, and test it on your end and try to implement it.

Updating JSON file NodeJS

This is my code:
const Discord = require('discord.js');
const client = new Discord.Client();
const TOKEN = "***********";
const PREFIX = "!";
client.on("ready", function () {
console.log("Ready!");
});
client.on("message", function (message) {
if (message.author.equals(client.user)) return;
if (!message.content.startsWith(PREFIX)) return;
var args = message.content.substring(PREFIX.length).split(" ");
switch (args[0]) {
case "rules":
var _embed = new Discord.RichEmbed()
.setTitle("Ruleset")
.addField("Where is my order?", "Theres only one proper way to recive an order and help. Its a command .ticket")
.addField("Why AZATEJ is such a bitch?", "If my status is 'dont disturb' and hue is way more red than green it means I have a reason to do so, im not a dick, but i recive a shitload of messages on daily route with stupid quiestions.")
.addField("Dont ask stupid questions", "Stupid doesnt mean basic, we are up to help you but before you'll contact anyone read twice explanation documents and use a ticket.")
.setColor(0x00FFFF)
.setFooter("This message is coool !")
.setThumbnail(message.author.avatarURL);
message.channel.send(_embed);
break;
case "spotify":
var uID = message.author.id;
for (let i = 0; i < ftpr.buyers.length; i++) {
if (uID === ftpr.buyers[i].id) {
var _embed = new Discord.RichEmbed()
.setTitle("Spotify")
.addField("Username", "testsda#yahoo.com")
.addField("Password", "ithastobe8")
.setColor(0x00FFFF)
.setFooter("Sincerely, LajgaardMoneyService")
.setThumbnail(message.author.avatarURL);
message.author.send(_embed);
console.log(message.author.username + "(" + JSON.stringify(ftpr.buyers[i].id) + ") Just used the command !spotify");
break;
}
else {
message.channel.send(message.author + "You haven't got a valid subscription. This command is locked until a new one is obtained!");
break;
}
}
break;
}
});
client.on('guildMemberAdd', function(member) {
console.log("User " + member.id + " has joined the server!");
//var role = member.guild.roles.find("name", "Google!");
var myRole = member.guild.roles.find("name", "Google!");
member.addRole(myRole);
});
client.login(TOKEN);
This is the JSON file:
{
"buyers": [
{
"id": "1331499609509724162"
},
{
"id": "181336616164392960"
},
{
"id": "266389854122672128"
}
]
}
When the bot is running and im changing one of the ID's the check function in case "spotify": is still using the old id. I do not want to restart the program every time the json file updates as it should be running 24/7. I have tried const fs = require("fs"); method but it gave me this error: TypeError: Cannot read property 'buyers' of undefined json
Sincerely, Oscar
const fs = require("fs"); just loads the module. Put that at the top of your file.
To read the json file each time you need to check user IDs (inefficient, but should get things working), put this at the top of your spotify case:
case "spotify":
var yourjsonfile = fs.readFileSync("yourjsonfile.json");
var ftpr = JSON.parse(yourjsonfile);
var uID = message.author.id;
for (let i = 0; i < ftpr.buyers.length; i++) {
if (uID === ftpr.buyers[i].id) {
Again, this is very inefficient - you are reloading the file every time you need to check it, and it uses readFileSync(), which blocks until the file is read (it is better to utilize node's asynchronous features). So as the JSON file grows larger, this will run slower. But at that point you probably need a database or some other mechanism for persisting and querying your data.

Loop through MySQL rows and store results in array

I am trying to store details of affectedRows from a MySQL INSERT query using NodeJS. My mind is melting trying to comprehend callbacks and Promises. Being a single-man dev team I wanted to reach out and ask for the clearest explanation as to how a callback can be applied here in a foreach loop.
The goal should be clear from these few lines of code; store data in the affected_rows[] array.
var affected_rows = [];
asset_array.forEach(function(asset) { // Populate the asset table
var query_string = "INSERT IGNORE INTO " + asset_table + " SET symbol = '" + asset[0] + "', name = '" + asset[1] + "'";
connection.query(query_string, function(err, rows, fields) {
if (err) throw err;
if ( rows.affectedRows > 0 ) {
data_to_push = [asset_table, asset[0], asset[1]];
affected_rows.push(data_to_push);
}
});
});
console.log(affected_rows); // [] for obvious async reasons
One option would be to process the asset_array inside a function and pass a callback into it and when loops through asset_array check if the current index matches the asset_array length (-1). If so call the callback.
var affected_rows = [];
function processAssets(cb) {
var array_len = asset_array_len.length
asset_array.forEach(function(asset, index) {
var query_string = 'INSERT IGNORE INTO ' + asset_table + ' SET symbol = \'' + asset[0] + '\', name = \'' + asset[1] + '\'';
connection.query(query_string, function(err, rows, fields) {
if (err) throw err
if (rows.affectedRows > 0) {
data_to_push = [asset_table, asset[0], asset[1]];
affected_rows.push(data_to_push);
}
if (index === (array_len - 1)) cb()
});
});
}
processAssets(function() {
console.log(affected_rows)
})
Will suggest you to have a look at async Queue.
You can change your code like this to use it.
//2nd Step - Perform each task and then call callback() to move to next task
var q = async.queue(function(query_string, callback) {
connection.query(query_string, function(err, rows, fields) {
if (err) throw err;
if ( rows.affectedRows > 0 ) {
data_to_push = [asset_table, asset[0], asset[1]];
affected_rows.push(data_to_push);
}
callback(); //call next task
});
}, 2); //here 2 means concurrency ie 2 tasks will run in parallel
//Final Step - Drain gives you end of queue which means all tasks have finished processing
q.drain = function() {
//Do whatever you want after all tasks are finished
};
//1st Step - create a queue of all tasks that you need to perform
for (var i = 0; i < asset_array.length ; i++) {
var query_string = "INSERT IGNORE INTO " + asset_table + " SET symbol = '" + asset[0] + "', name = '" + asset[1] + "'";
q.push(query_string);
}

Getting response with NodeJS request module

I just started using the twitch kraken api and I have a few questions.
Whenever I attempt to get a JSON object there is no response. I am attempting to run this function through Amazon AWS Lambda, and don't have access to a console.
In the code below my callback function will always print out "SUCCESS got streamers ERROR". I am pretty certain right now the "ERROR" comes from my initial setting of result.
How come result does not get changed into the proper JSON?
I have used postman and it returns the proper thing with the query and param, and headers:
function getJSON(callback){
var result = "ERROR";
request.get(url(games[0]),function(error,response,body){
console.log("requested for url: " + url(games[0]));
var d = JSON.parse(body);
result = d.streams[0];//.channel.display_name;
// for(var i = 0; i < limit; i++){
// streamers.push(d.streams[i].channel.display_name)
// }
streamers.push(result);
});
if (streamers.length < 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
}
function url(game){
return {
url: "https://api.twitch.tv/kraken/streams/",//twitchlimit,
qs : {
'game' : 'overwatch',
'limit' : 2
},
headers: {
'Client-ID': clientID,
'Accept': 'application/json',
'Accept-Charset': 'utf-8',
}
};
}
I think your streamers code
if (streamers.length < 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
should be included in the request callback because currently it's not waiting for the request to finish, it's just carrying on so therefore the value of result will not change. Also the array length cannot be less than 0 so it will always go to the else and say "SUCCESS got streamers ERROR"
Thank you guys for the suggestions. I did have a few oversights and attempted to fix them.
I have implemented you suggestions and it seems to have worked a bit. I ended up putting the json.parse into a try/catch block, and moved the if/else statements inside the getJSON method. However, now I don't get any output.
This is how I am invoking the getJSON method:
function handleGameResponse(intent,session,callback){
//gets the game
var game = intent.slots.game.value;
if (!games.includes(game)){
var speechOutput = "You asked for: " + intent.slots.game.value;
//var speechOutput = "You asked for: " + games[game] + " That game is currently not an option. These are your current options: " + arrayToString(games)
var repromptText = "Please ask one from the current options.";
var header = "Invalid Game";
}else {
getJSON(function(data){
if(data !== "ERROR"){
var speechOutput = data; //capitalizeFirst(game) + " top three streamers are: " + arrayToString(streamers) + '.';
var repromptText = "Do you want to hear more about games?";
var header = capitalizeFirst(game);
}else{
var speechOutput = "I'm sorry, something went wrong and I could not get the streamers.";
}
//speechOutput = data;
});
//speechOutput = games[0] + " games[0], game= " + game; //this executes so the getJSON isn't executing
}
var shouldEndSession = false;
callback(session.attributes,buildSpeechletResponse(header,speechOutput,repromptText,shouldEndSession));
}
Does the above execute the same way? As in the shouldEndSession and callback execute before the getJSON has time to give a response?
For ref, this is the getJSON method now:
function getJSON(callback){
var result = "ERROR";
request.get(url(games[0]),function(error,response,body){
try{
var d = JSON.parse(body);
} catch (err){
callback("Sorry, something seems to have malfunctioned while getting the streamers");
}
result = d.streams[0].channel.display_name;
// for(var i = 0; i < limit; i++){
// streamers.push(d.streams[i].channel.display_name)
// }
streamers.push(result);
if (streamers.length <= 0){
callback("ERROR");
}else{
callback("SUCCESS got streamers " + result);
}
});
}

multiple async mongo request generate messed up returns

I'm trying to build a JSON out of multiple requests on my mongodb.
since I'm not using DBRef, I have to build the "table joints" by myself, and that's how I ended up in this mess.
This is the code that is giving me the headaches from a couple of days now.
(the mongo part is done with mongoskin)
var getUserFeed = function(thelimit, out) {
userfeed = db.collection("userfeed");
apparel = db.collection("apparel");
store = db.collection("stores");
if(thelimit)
args = {limit:thelimit, sort: [['date',-1]]};
userfeed.find({},args).toArray(function(e, feed) {
if (e) console.log("error: ", e);
// gather aparel infos
var i=0;
var ret_feeds = [];
feed.forEach(function(cur_feed) {
var outfits=[];
console.log("beginning with: " + cur_feed.url);
var resfeed = "";
resfeed = cur_feed;
resfeed.url = baseurl + snapurl + resfeed.url + "_small.jpg";
i=0;
cur_feed.apparel_ids.forEach(function(item) {
/*>>*/ apparel.find({"_id": item},{limit:1}).toArray(function(e, results) {
console.log(">>>>>>>>>>> APPAREL_FIND { i:" + i + "}");
if (e) console.log("error: ", e);
results = results[0];
if(results.apparel_cat == 1)
url_subcat = "pants/";
else if(results.apparel_cat == 2)
url_subcat = "shirts/";
else if(results.apparel_cat == 2)
url_subcat = "tshirts/";
results.thumb = baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg";
results.size = "M"; ///// TOBE REAL VERY SOON
results.gallery = [
baseurl + outfiturl + url_subcat + results.apparel_id + "/model.jpg",
baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg"
];
outfits.push(results); // quick and dirty, 2 b refined..
i++;
if(i>=cur_feed.apparel_ids.length)
{
// pack it up
// resfeed.url = resfeed.url;
resfeed.outfits = outfits;
resfeed.fav = false;
resfeed.bough = false;
// retrieve store infos
/*>>>*/ store.find({"_id":resfeed.store_id}, {limit: 1}).toArray(function(e, resstore) {
console.log("\t############# STORE_FIND { i:" + i + "}");
if (e) console.log("error: ", e);
resfeed.store = resstore[0];
resfeed.store.class = "hem";
ret_feeds.push(resfeed);
if(ret_feeds.length >= feed.length)
{
console.log("\t\t######################calling return [ ret_feeds.length = " + ret_feeds.length + " feed.length = " + feed.length);
out.send(ret_feeds);
}
});
}
});
});
});
});
}
This code fails, because returns the json before finishing its task, so the next time that it tries to return another json it crashes miserably due to the fact the the headers have already been sent.
Now as you can see, I have 3 collections: userfeed, apparel and stores.
the goal of this function is to retrieve all the items in the userfeed collection, extract the outfits (based on the outfit_id array that is part of the userfeed collection), and also extract the store infos related in the same way to each userfeed entry, like so:
I know that async.js or equivalent is the way to go: I've red like a gazillion of other posts here on SO, but I still can't get my head around it, probably because the whole mechanism behind the async.js or flow control in general it's still out of focus in my mind.
I'm still a noob at node :)
UPDATE
I think I found the right path for understanding here: http://www.sebastianseilund.com/nodejs-async-in-practice
this guy made a terrific job in describing use-case by use-case all the ways to apply async.js to your code.
I'll post the solution as soon as I get around it.
UPDATE 2
Thanks to the above dude I could work out a working solution, below is the answer.
After so much struggling I have finally managed to get a solution.
async.js was the answer as I was (obviously) suspecting.
FYI here's the working code.
If you like to point out improvements or anything else, you are more than welcome
var getUserFeed = function(thelimit, out) {
userfeed = db.collection("userfeed");
apparel = db.collection("apparel");
store = db.collection("stores");
var args;
if(thelimit)
args = {limit:thelimit, sort: [['date',-1]]};
var outfits=[];
var feeds = array();
async.series([
// userfeed find
function(callback) {
userfeed.find({},args).toArray(function(e, feed) {
if(e) callback(e);
feeds = array(feed);
console.log(feeds.length + " retrieved. stepping in");
callback(null, null);
});
},
// join
function(callback) {
async.forEach(feeds, function(thefeed, callback) {
var i = feeds.indexOf(thefeed);
async.parallel([
// load apparel infos
function(callback) {
console.log("\t >>> analyzing thefeed id " + thefeed._id);
async.forEach(thefeed.apparel_ids, function(apparel_id, callback) {
apparel.find({"_id": apparel_id},{limit:1}).toArray(function(e, results) {
if (e) console.log("error: ", e);
results = results[0];
if(results.apparel_cat == 1)
url_subcat = "pants/";
else if(results.apparel_cat == 2)
url_subcat = "shirts/";
else if(results.apparel_cat == 2)
url_subcat = "tshirts/";
results.thumb = baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg";
results.size = "M"; ///// TOBE REAL VERY SOON
results.gallery = [
baseurl + outfiturl + url_subcat + results.apparel_id + "/model.jpg",
baseurl + outfiturl + url_subcat + results.apparel_id + "/front.jpg"
];
console.log("\t\t### pushing data into thefeed_index: " + i);
if(!util.isArray(feeds[i].oufits)) feeds[i].outfits = array();
feeds[i].outfits.push(results);
callback(null, null);
});
}, callback);
},
// load store infos
function(callback) {
store.find({"_id":thefeed.store_id}, {limit: 1}).toArray(function(e, resstore) {
console.log("\t### STORE_FIND");
if (e) console.log("error: ", e);
feeds[i].store = resstore[0];
feeds[i].store.class = "hem";
callback(null, null);
});
}
], callback);
}, callback);
}
// MAIN
], function(err, result) {
console.log("feed retrieval completed. stepping out");
if (err) return next(err);
out.send(feeds);
});
};