Undefined results when using imported custom nodejs module - javascript

I am trying to search my local db for a user by email, but when I try to reference a function that does that from a different js file, via an import, I get undefined results. I have searched a bit on Stack about this issue I am having, and heard of something referred to as a callback, is this something that I would need to implement? If so could you point me to an example ?
Thanks in advance!
Here is my code that is exported (db.js file) :
var neo4j = require('neo4j-driver').v1;
var driver = neo4j.driver("bolt://localhost:7687", neo4j.auth.basic("neo4j", "neo4j"));
var session = driver.session();
exports.findEmail = (email) => {
// console.log('hi');
session
.run("MATCH (a:Person) WHERE a.email = {email} RETURN a.name AS name, a.email AS email, a.location AS location", {
email: email
})
.then((result) => {
let result_string = '';
result.records.forEach((record) => {
console.log(record._fields);
result_string += record._fields + ' ';
});
return result_string;
})
.catch((e) => {
return ('error : ' + JSON.stringify(e));
})
}
Here is my code calling the export : (test.js)
var tester = require('./db.js');
let temp = tester.findEmail("testemail#yahoo.com");
console.log(temp);

The thing is that JS is asynchronous, and you using it as it is synchronous code.
Can you try this one, should work:
var neo4j = require('neo4j-driver').v1;
var driver = neo4j.driver("bolt://localhost:7687", neo4j.auth.basic("neo4j", "neo4j"));
var session = driver.session();
const findEmail = (email, callback) => {
console.log('hi :', email);
session
.run("MATCH (a:Person) WHERE a.email = {email} RETURN a.name AS name, a.email AS email, a.location AS location", {
email: email
})
.then((result) => {
let result_string = '';
result.records.forEach((record) => {
console.log(record._fields);
result_string += record._fields + ' ';
});
return callback(null, result_string);
})
.catch((e) => {
return callback('error : ' + JSON.stringify(e)));
})
}
module.exports = {
findEmail
};
Then in test.js:
var tester = require('./db');
tester.findEmail("testemail#yahoo.com", (err, temp) => {
if (err) return console.error(err);
console.log(temp);
} );
The idea behind this is that all the flow in db file is asynchronous.
So in order to catch result you need to pass the function, callback, which will be triggered when the ansynchronous flow is done.

Related

How to save thousand data in Parse Platform NodeJS

I am new to the parse platform and i'm trying to insert 81000 rows of data in to the Parse DB, here the code
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
var kp = new Parse.Object("theClass");
kp.save(datakp)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
})
}
There is no error in console log, and no data is saved in Parse DB, but if I only insert 1000 rows, it will save to the database.
EG:
if (dataresult.length > 0) {
res.data.forEach(function (datakp, index) {
if (index < 1000) {
var kp = new Parse.Object("theClass");
kp.save(datakp)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
})
}
}
Thank You
UPDATE
I fix this case based on answer #davi-macêdo
here a complete code
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
const objs = [];
const theKP = Parse.Object.extend("theClass")
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
var thekp = new theKP()
thekp.set(datakp)
objs.push(thekp);
})
}
Parse.Object.saveAll(objs)
.then((res) => {
console.log('oke updated ' + dataresult.length)
}),
(error) => {
console.log('err : '+ error.message)
}
The most efficient way is using Parse.Object.saveAll function. Something like this:
const uri = "/the.json"
const res = await axios.get(uri)
const dataresult = Object.keys(res.data)
const objs = [];
if (dataresult.length > 0) {
res.data.forEach(function (datakp) {
objs.push(new Parse.Object("theClass", datakp));
})
}
Parse.Object.saveAll(objs)
.then((res) => {
console.log('oke ' + res.id)
}),
(error) => {
console.log('err : '+ error.message)
}
Anyways, since you have no error and no data currently being saved, you might be kitting some memory limit. So that's something you also need to be aware about.
You're probably hitting rate limits, I can't imagine saving 81,000 records in one shot is normal behaviour for many applications.
I looked through the documentation and couldn't find anything that might mention a save limit, however sending 1000 requests would trigger most rate limit protection

CypressIO Returning string value from cy.task() using cy.wrap() gives error "cy is not defined"

In cypress /plugins/index.js I have code to query oracleDB
module.exports = (on, config) => {
on('task', {
'registration': async (email) => {
const oracledb = require('oracledb');
oracledb.initOracleClient({libDir: './oracleClient'});
let result;
let connection;
connection = await oracledb.getConnection( {
user : process.env.ORACLEDB_USER,
password : process.env.ORACLEDB_PASSWORD,
connectString : "localhost/STORE"
});
result = await connection.execute(
"select ..."
);
console.log(result.rows)
var extractedUrlText = JSON.stringify((await result).rows).extract('/VerifiedRegistrationFormView','\"');
console.log('Extracted URL: \r\n' + extractedUrlText);
return cy.wrap(extractedUrlText);
}
});
}
This returns the correct extracted URL in Node terminal.
But then in my cypress test, when I try to use that extractedUrlText string value i'm getting error cy is not defined:
it('Register a new user', () => {
cy.task('registration', emailAddress, { timeout: 10000 }).then(value => cy.log(value)) // cy is not defined
})
I use a similiar approach to use a returned value from support/commands.js Cypress.Commands.add() and it works there, but not from cy.task() using cy.wrap()
My working solution:
/plugins/index.js extended from above code:
var extractedUrlText = JSON.stringify((await result).rows).extract('/VerifiedRegistrationFormView','\"');
console.log('Extracted NODE URL: \r\n' + extractedUrlText);
return extractedUrlText
}
In spec file:
let extractedUrl;
cy.task('registration', emailAddress).then(value => {
extractedUrl = value;
cy.log('Extracted CY URL: ' + extractedUrl)
})
Result:

API distance matrix Call in Javascript alone

So I am an extremely beginner programmer trying to understand how to call/get data from Google Distance Matrix API in purely Javascript.
Below is my codes
https = require('https')
function getDistance(app){
console.log('testing1');
let defaultPath = 'maps.googleapis.com/maps/api/distancematrix/json?units=metric';
let APIKey = '&key=<API KEY HERE>';
let origin = 'Tampines Avenue 1, Temasek Polytechnic';
let destination = 'Tampines Central 5, Tampines Mall';
let newPath = defaultPath+ '&origins=' + origin + '&destinations=' +destination + APIKey;
console.log('https://'+ newPath); //this prints the correct path
https.get('https://'+ newPath, (res) =>{ //i assume the problem begins here?
console.log('testing2')//doesnt print
let body = ''; //no idea what this does. Copied from a school lab sheet
res.on('data', (d) => {
console.log('testing3') //this doesn't print
let response = JSON.parse(body);
let distance = response.rows[0].elements.distance.text //are these correct?
let travelTime = response.rows[0].elements.duration.text
console.log(distance) //doesnt print
console.log(response.rows[0]) //doesnt print
app.add('distance between is ' + distance + '. Time taken is ' + travelTime);
console.log(response);
});
});
}
I'm pretty sure the 'https://'+ newPath is correct as it is printed in the console.log
And throwing the link into a browser
I get this as result
so can someone please explain to me what i'm doing wrong?
Oh and also, dont know if this is necessary but im doing this in dialogflow.cloud.google.com as a chatbot for my assignment
This is the error I get
Error: No responses defined for platform: undefined at
WebhookClient.send_
(/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:428:13)
at promise.then
(/srv/node_modules/dialogflow-fulfillment/src/dialogflow-fulfillment.js:246:38)
at at process._tickDomainCallback
(internal/process/next_tick.js:229:7)
I found a similar problem on GitHub: https://github.com/dialogflow/dialogflow-fulfillment-nodejs/issues/22
The solution was
Okay, so here's what I did to make this work properly.
I used request-promise-native instead of http to make the AJAX Call.
const rp = require('request-promise-native');
I returned a promise from the handler of the promise that rp returns.
return rp(options).then(data => { // Extract relevant details from data. // Add it to the agent. agent.add('Here's the data: ', JSON.stringify(data)); return Promise.resolve(agent); });
The full code is
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const rp = require('request-promise-native');
const { WebhookClient } = require('dialogflow-fulfillment');
const { Card, Suggestion } = require('dialogflow-fulfillment');
const { Carousel } = require('actions-on-google');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
const imageUrl = 'https://developers.google.com/actions/images/badges/XPM_BADGING_GoogleAssistant_VER.png';
const imageUrl2 = 'https://lh3.googleusercontent.com/Nu3a6F80WfixUqf_ec_vgXy_c0-0r4VLJRXjVFF_X_CIilEu8B9fT35qyTEj_PEsKw';
const linkUrl = 'https://assistant.google.com/';
const API_KEY = 'YOUR-API-KEY-HERE';
const server = express();
server.use(
bodyParser.urlencoded({
extended: true
})
);
server.use(bodyParser.json());
server.post('/dialog-flow-fulfillment', (request, response) => {
const agent = new WebhookClient({ request, response });
function googleAssistantOther(agent) {
let conv = agent.conv();
conv.ask(`Sure! Details about ${agent.parameters.movie} coming your way!`);
return getMovieDataFromOMDb(agent.parameters.movie).then(movie => {
conv.ask(`Okay! So there you go.`);
conv.ask(new Card({
title: `${movie.Title}(${movie.Year})`,
imageUrl: movie.Poster,
text: `${movie.Rated} | ${movie.Runtime} | ${movie.Genre} | ${movie.Released} (${movie.Country})`,
buttonText: 'Website',
buttonUrl: movie.Website || `https://www.imdb.com/title/${movie.imdbID}`
}));
conv.ask(new Suggestion(`More details`));
conv.ask(new Suggestion(`Another movie`));
agent.add(conv);
return Promise.resolve(agent);
});
}
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function getMovieDetailsOther(agent) {
return getMovieDataFromOMDb(agent.parameters.movie).then(movie => {
// const responseDataToSend = `${movie.Title} is a ${
// movie.Actors
// } starer ${movie.Genre} movie, released in ${
// movie.Year
// }. It was directed by ${movie.Director}`;
// console.log(`Generated response as ${responseDataToSend}`);
// agent.add(responseDataToSend);
agent.add(`Okay! So there you go.`);
agent.add(new Card({
title: `${movie.Title}(${movie.Year})`,
imageUrl: movie.Poster,
text: `${movie.Rated} | ${movie.Runtime} | ${movie.Genre} | ${movie.Released} (${movie.Country})`,
buttonText: 'Website',
buttonUrl: movie.Website || `https://www.imdb.com/title/${movie.imdbID}`
}));
agent.add(new Suggestion(`More details`));
agent.add(new Suggestion(`Another movie`));
return Promise.resolve(agent);
}, error => {
console.log(`Got an error as ${error}`);
agent.add(`Sorry bout that! An error prevented getting data for: ${agent.parameters.movie || 'the requested movie'}`
);
})
.catch(function (err) {
console.log(`Caught an err as ${err}`);
agent.add(err);
});
// agent.add(`This message is from Dialogflow's Cloud Functions for Firebase editor!`);
// const newCard = new Card({
// title: `Title: this is a card title`,
// imageUrl: imageUrl,
// text: `This is the body text of a card. You can even use line\n breaks and emoji! 💁`,
// buttonText: 'This is a button',
// buttonUrl: linkUrl
// });
// // newCard.setPlatform('facebook');
// agent.add(newCard);
// agent.add(new Suggestion(`Quick Reply`));
// agent.add(new Suggestion(`Suggestion`));
// agent.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
}
function moreDetailsOther(agent) {
return getMovieDataFromOMDb(agent.parameters.movie).then(movie => {
agent.add(`Okay! I've got you covered on this too.`);
agent.add(`So the ${movie.Actors} starer ${movie.Type} is produced by ${movie.Production}, is directed by ${movie.Director}`);
agent.add(`It ${movie.Awards}. It's available in ${movie.Language}`);
agent.add(`Written by ${movie.Writer}, it plots ${movie.Plot}`);
agent.add(new Suggestion(`Stats on the movie`));
agent.add(new Suggestion(`Another movie`));
return Promise.resolve(agent);
}, error => {
console.log(`Got an error as ${error}`);
agent.add(`Sorry bout that! An error prevented getting data for: ${agent.parameters.movie || 'the requested movie'}`
);
})
.catch(function (err) {
console.log(`Caught an err as ${err}`);
agent.add(err);
});
}
function movieStatsOther(agent) {
return getMovieDataFromOMDb(agent.parameters.movie).then(movie => {
let ratingDetails = `${movie.Title} scored `;
movie.Ratings.forEach(rating => {
ratingDetails += `${rating.Value} on ${rating.Source} `
});
agent.add(`Sure! Here are the stats.`);
agent.add(ratingDetails);
agent.add(new Suggestion(`Another movie`));
return Promise.resolve(agent);
}, error => {
console.log(`Got an error as ${error}`);
agent.add(`Sorry bout that! An error prevented getting data for: ${agent.parameters.movie || 'the requested movie'}`
);
})
.catch(function (err) {
console.log(`Caught an err as ${err}`);
agent.add(err);
});
}
function getMovieDataFromOMDb(movieName) {
const movieToSearch = movieName || 'The Godfather';
const options = {
uri: 'https://www.omdbapi.com/',
json: true,
qs: {
t: movieToSearch,
apikey: API_KEY
}
};
return rp(options);
}
// Run the proper handler based on the matched Dialogflow intent
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) {
intentMap.set(null, googleAssistantOther);
// intentMap.set('More Details', googleAssistantMoreDetails);
// intentMap.set('Movie Stats', googleAssistantMovieStats);
} else {
intentMap.set('Get Movie Details', getMovieDetailsOther);
intentMap.set('More Details', moreDetailsOther);
intentMap.set('Movie Stats', movieStatsOther);
}
agent.handleRequest(intentMap);
});
server.listen(process.env.PORT || 8000, () => {
console.log('Server is up and running...');
});
Codepen: https://codepen.io/siddajmera/pen/eraNLW?editors=0010
You don't show all your code, but it looks like getDistance() is your Intent Handler function that you've registered in code that you're not showing.
If so, and if you're making an asynchronous call to an API, you need to return a Promise to indicate that you're waiting for the HTTP call to complete before you send the result.
Without the Promise, the function completes right after it makes the call with http.get(), but without anything being set for the response with app.add().
While it is possible to turn an event-based call (what you're doing now) into a Promise, it isn't that easy if you're not familiar with it, and there are better solutions.
Using a package such as request-promise (and more likely request-promise-native - it uses the same syntax, but request-promise has the documentation) is far easier. With this, you would return the Promise that is generated by the http call, and in the then() clause of it, you would make your calls to app.add().
I haven't tested it, but it might look something like this:
const rp = require('request-promise-native');
function getDistance(app){
console.log('testing1');
let defaultPath = 'maps.googleapis.com/maps/api/distancematrix/json?units=metric';
let APIKey = '&key=<API KEY HERE>';
let origin = 'Tampines Avenue 1, Temasek Polytechnic';
let destination = 'Tampines Central 5, Tampines Mall';
let newPath = defaultPath+ '&origins=' + origin + '&destinations=' +destination + APIKey;
let url = 'https://'+newPath;
console.log(url);
rp.get(url)
.then( response => {
console.log(response);
let distance = response.rows[0].elements.distance.text
let travelTime = response.rows[0].elements.duration.text
app.add('distance between is ' + distance + '. Time taken is ' + travelTime);
})
.catch( err => {
console.log( err );
app.add('Something went wrong.');
});
};

TypeError: Cannot read property 'json' of undefined google assistant

I'm working on a Bus Stop google assistant script in node.js
I based it on the weather API example by Google. Given the right API key, the weather function will work and return the weather for a place on a date.
The Bus Stop API will return the correct output in the console.log, but the output does not get passed on to the else if statement where the function is called.
I get 2 errors:
"Unhandled rejection" Which can be alleviated by commenting out the reject code in the callBusApi.
"TypeError: Cannot read property 'json' of undefined
at callBusApi.then.catch (/user_code/index.js:45:9)
at process._tickDomainCallback (internal/process/next_tick.js:135:7)" This is where it breaks. I think because it doesn't get the output from the function.
My script looks as follows:
'use strict';
const http = require('http');
const host = 'api.worldweatheronline.com';
const wwoApiKey = 'enter a working key';
exports.weatherWebhook = (req, res, re) => {
if(req.body.queryResult.intent['displayName'] == 'weather'){
// Get the city and date from the request
let city = req.body.queryResult.parameters['geo-city']; // city is a required param
// Get the date for the weather forecast (if present)
let date = '';
if (req.body.queryResult.parameters['date']) {
date = req.body.queryResult.parameters['date'];
console.log('Date: ' + date);
}
// Call the weather API
callWeatherApi(city, date).then((output) => {
res.json({ 'fulfillmentText': output }); // Return the results of the weather API to Dialogflow
}).catch(() => {
res.json({ 'fulfillmentText': `I don't know the weather but I hope it's good!` });
});
}
else if (req.body.queryResult.intent['displayName'] == 'mytestintent'){
callBusApi().then((output) => {
re.json({ 'fulfillmentText': output }); // Return the results of the bus stop API to Dialogflow
}).catch(() => {
re.json({ 'fulfillmentText': `I do not know when the bus goes.` });
});
}
};
function callBusApi () {
return new Promise((resolve, reject) => {
http.get({host: 'v0.ovapi.nl', path: '/stopareacode/beunav/departures/'}, (re) => {
let boy = '';
re.on('data', (d) => {boy+=d});
re.on('end',() => {
let response = JSON.parse(boy)
var firstKey = Object.keys(response['beunav']['61120250']['Passes'])[0];
var timeKey = Object.keys(response['beunav']['61120250']['Passes'][firstKey])[19];
var destKey = Object.keys(response['beunav']['61120250']['Passes'][firstKey])[1];
let destination = response['beunav']['61120250']['Passes'][firstKey][destKey];
let datetime = response['beunav']['61120250']['Passes'][firstKey][timeKey];
let fields = datetime.split('T');
let time = fields[1];
let output = `Next bus to ${destination} departs at ${time} .`;
console.log(output)
resolve(output);
});
re.on('error', (error) => {
console.log(`Error talking to the busstop: ${error}`)
reject();
});
});
});
};
function callWeatherApi (city, date) {
return new Promise((resolve, reject) => {
let path = '/premium/v1/weather.ashx?format=json&num_of_days=1' +
'&q=' + encodeURIComponent(city) + '&key=' + wwoApiKey + '&date=' + date;
console.log('API Request: ' + host + path);
http.get({host: host, path: path}, (res) => {
let body = '';
res.on('data', (d) => { body += d; });
res.on('end', () => {
let response = JSON.parse(body);
let forecast = response['data']['weather'][0];
let location = response['data']['request'][0];
let conditions = response['data']['current_condition'][0];
let currentConditions = conditions['weatherDesc'][0]['value'];
let output = `Current conditions in the ${location['type']}
${location['query']} are ${currentConditions} with a projected high of
${forecast['maxtempC']}°C or ${forecast['maxtempF']}°F and a low of
${forecast['mintempC']}°C or ${forecast['mintempF']}°F on
${forecast['date']}.`;
console.log(output);
resolve(output);
});
res.on('error', (error) => {
console.log(`Error calling the weather API: ${error}`)
reject();
});
});
});
}
It appears that your method has a parameter too much
exports.weatherWebhook = (req, res, re) => {
should be:
exports.weatherWebhook = (req, res) => {
And as well on the variable 're' used in the handling of the 'mytestintent' inside the webhook.
This explains the 'not defined' error when trying to set a json value on it.
Regarding your 2 question: It usually comes when the value of the variable is not defined.
First check wheather you have defined the JSON variable in your .js file.
Or its in some other format.

Firebase error while resolving a bunch of promises: Cannot convert undefined or null to object

I have an error from firebase while running a cloud function :
FIREBASE WARNING: Exception was thrown by user callback. TypeError:
Cannot convert undefined or null to object
Here is a snippet where the error probably occurs :
// const functions = require('firebase-functions');
// const admin = require('firebase-admin');
// const underscore = require('underscore');
// admin.initializeApp(functions.config().firebase);
// export updateSimilars = functions.database.ref('...').onWrite(event => {
...
for (var i in callerFlattenLikesDislikes) {
getOtherUsersPromises.push(getOtherUsersFromName(callerFlattenLikesDislikes[i], genre));
}
console.log('getOtherUsersPromises length: ' + getOtherUsersPromises.length);
return Promise.all(getOtherUsersPromises).then(dataArr => {
console.log(dataArr); // will never fire
dataArr.forEach(data => {
data.forEach(user => {
if (otherUsers.indexOf(user) > -1 && user !== userId) {
otherUsers.push(user);
}
});
});
....
....
function getOtherUsersFromName(name, genre) {
console.log('fired getOtherUsersFromName: ' + name);
return new Promise((resolve, reject) => {
admin
.database()
.ref('/names/' + genre + '/' + name)
.once('value', snapshot => {
var dic = snapshot.val();
var dislikingUsers = Object.keys(dic['dislikingUsers']);
var likingUsers = Object.keys(dic['likingUsers']);
var users = underscore.union(dislikingUsers, likingUsers);
console.log('will resolve: ' + users);
resolve(users);
});
});
}
Basically, I have an array of promises to be executed asynchronously (the same firebase query for several input items).
I want to gather all the results before starting to process them.
But the .then after Promise.all seems to never be fired, and I have the following firebase logs:
Anyone to help me ?
Thanks !
I think you need to check a name exist or not at the path '/names/' + genre + '/' + name. It gives an error when this path is empty.
function getOtherUsersFromName(name, genre) {
console.log('fired getOtherUsersFromName: ' + name);
return new Promise((resolve, reject) => {
admin
.database()
.ref('/names/' + genre + '/' + name)
.once('value', snapshot => {
if (snapshot.exists()){
var dic = snapshot.val();
var dislikingUsers = Object.keys(dic['dislikingUsers']);
var likingUsers = Object.keys(dic['likingUsers']);
var users = underscore.union(dislikingUsers, likingUsers);
console.log('will resolve: ' + users);
resolve(users);
} else {
// Do something as the path is empty
}
});
});
}

Categories

Resources