I think I'm missing something simple here but think that I've been looking at this too long.
I originally had what you see here in the function inline, but would like to pull it out and use it in other aspects of my app, but I can't seem to get the intended information into the POST response.
Here's my function:
let lookUpUserId = (x) => {
mongo.connect(url, (err,db) => {
assert.equal(null,err);
db.collection('data').findOne({"email": {'$eq' : x }},{"_id":1}, (err,result) => {
console.log(result); // I'm getting the correct response here.
assert.equal(null,err);
db.close();
return result; // This seems to be returning empty
});
});
};
And now here's where I'm calling it (simplified):
router.post('/test1', (req,res,next) => {
console.log('Hit on POST /test1');
let obj = 'email#email.com';
let a = lookUpUserId(obj);
res.send(a);
});
Now in the server's console I'm getting the expected info:
{_id:someIdHere }
However, I'm getting an empty body in response to my POST on the client side.
Can anyone point me in the right direction here.
lookUpUserId works asynchronously. Since you're not using promises, you can pass a callback as a second argument of lookUpUserId function:
let lookUpUserId = (x, callback) => {
mongo.connect(url, (err,db) => {
assert.equal(null,err);
db.collection('data').findOne({"email": {'$eq' : x }},{"_id":1}, (err,result) => {
console.log(result);
assert.equal(null,err);
db.close();
callback(result);
});
});
};
and call it with:
lookUpUserId(obj, (result) => res.send(result));
or even:
lookUpUserId(obj, res.send);
Related
i have the following code in nodejs:
const unifi = require('node-unifi');
const controller = new unifi.Controller(IP_ADDRESS, 8443);
function login(apiCall) {
controller.login(USERNAME, PASSWORD, function (err) {
if (err) {
console.log('ERROR: ' + err);
return;
}
apiCall();
});
}
function getAllClients(site) {
login(function () {
controller.getClientDevices(site, (res, data) => {
console.log(data);
});
});
}
getAllClients('siteid');
In original call, any function needs to be called within login() so it can only be called while logged in.
When i call the function getAllCients(siteID) i get desired result in console.log. But for love of god I can't get the result returned from the function in another file where I required the said function. Always get undefined.
I assume I need to use a callback but after reading multiple forums (i.e. art of node) I am no wiser were to have the callback.
Any help would be appreciated.
Thanks to #VLAZ who pointed me in the right direction :-)
my code after edit:
function getAllClients(site) {
return new Promise(function (resolve, reject) {
login(function () {
controller.getClientDevices(site, (err, data) => {
if (!err) {
resolve(data);
}
});
});
});
}
all i changed was returning promise which i then consume in another file with .then()
Thank you!
I have a function which fetch a data from Firestore :
getLastTime(collectionName: string) {
const docRef = this.afs.firestore.collection(collectionName).doc(this.User).collection('lastTime').doc('lastTime');
docRef.get().then(doc => {
if (doc.exists) {
this.get = doc.data().lastTime;
} else {
this.get = 'Never done';
}
}).catch(error => {
console.log('Error getting document:', error);
});
return this.get;
}
For my test I actually have a string value inside the doc 'lastTime' which is a string.
Inside ngOnInit(), I called my function and console.log the result
this.InjuredLastTime = this.getLastTime('INJURY');
console.log(this. this.InjuredLastTime);
Normally I should have my string printed inside the console but I got undefined...
Maybe it's because Firestore do not fetch fast enough my data, but I am quiet surprised since Firestore is quiet fast normally...
You don't actually wait for the promise that is created by docRef.get() before you return from getLastTime(). So, unless the call to firebase is instant (e.g. never) this won't work.
The correct solution really depends on what you are doing with this.InjuredLastTime. But one approach would just be to return a promise and set it after it is ready:
getLastTime(collectionName: string) {
const docRef = this.afs.firestore.collection(collectionName).doc(this.User).collection('lastTime').doc('lastTime');
return docRef.get().then(doc => {
if (doc.exists) {
return doc.data().lastTime;
} else {
return 'Never done';
}
}).catch(error => {
console.log('Error getting document:', error);
return null;
});
}
Then, instead of the assignment synchronously, do it asynchronously:
this.getLastTime('INJURY').then(result => { this.InjuredLastTime = result });
Data is loaded from Firestore asynchronously, since it may take some time before the data comes back from the server. To prevent having to block the browser, your code is instead allowed to continue to run, and then your callback is called when the data is available.
You can easily see this with a few well-placed log statements:
const docRef = this.afs.firestore.collection(collectionName).doc(this.User).collection('lastTime').doc('lastTime');
console.log('Before starting to get data');
docRef.get().then(doc => {
console.log('Got data');
});
console.log('After starting to get data');
If you run this code, you'll get:
Before starting to get data
After starting to get data
Got data
This is probably not the order that you expected the logging output in, but it is actually the correct behavior. And it completely explains why you're getting undefined out of your getLastTime function: by the time return this.get; runs, the data hasn't loaded yet.
The simplest solution in modern JavaScript is to mark your function as async and then await its result. That would look something like this:
async function getLastTime(collectionName: string) {
const docRef = this.afs.firestore.collection(collectionName).doc(this.User).collection('lastTime').doc('lastTime');
doc = await docRef.get();
if (doc.exists) {
this.get = doc.data().lastTime;
} else {
this.get = 'Never done';
}
return this.get;
}
And then call it with:
this.InjuredLastTime = await this.getLastTime('INJURY');
I have a function that makes an API request and receives data in json format.
async function getDataAboutWeather(url) {
return await new Promise(resolve => {
request(url, (err, res, body) => {
if (err) {
throw new Error(err);
};
const info = JSON.parse(body);
resolve(info);
});
});
};
I want to write a test for this function.
describe('getDataAboutWeather function', () => {
it('The request should success', () => {
const link = 'http://ip.jsontest.com';
expect(getDataAboutWeather(link)).to.eql({});
});
});
How to verify that my function works as it should?
Since at the moment I get an error.
AssertionError: expected {} to deeply equal {}
getDataAboutWeather is an asynchronous function which means it returns a Promise. I would change the test to:
it('The request should success', async () => {
const link = 'http://ip.jsontest.com';
expect(await getDataAboutWeather(link)).to.eql({});
});
To test your function, you need to check if the API JSON is equal to the expected JSON. You can use the function below.
_.isEqual(object, other);
More information on this: How to determine equality for two JavaScript objects?
I'm currently struggling to get variable values from one node.js module into another. This is my current problem:
I am fetching data from a REST API via https-request:
// customrequest.js
sendRequest( url, function( data, err ) {
if(err) {
console.log('--- Error ---');
console.log( err );
}
else {
console.log('--- Response ---');
console.log(data);
// output: data
return data;
}
module.exports = { sendRequest }
And my index.js file:
// index.js
let sendRequest = require('./customrequest');
let req;
req = sendRequest('google.com');
console.log(req);
// output: undefined
// how can I get the variable set, when request is getting data in response?
I totally understand, that the request to an API takes some time for the response. One solution is, that I just put everything into one js file. But as my project will get bigger over time, the modular approach is my goto-solution. Any suggestions on how to solve this?
Node uses callbacks for this situation. Try something like this:
// customrequest.js
sendRequest(url, callback)
module.exports = { sendRequest }
// index.js
let sendRequest = require('./customrequest');
let req = sendRequest('google.com', function (data, err) {
if (err) {
//handle error here
}
console.log(data);
};
// output: undefined
// how can I get the variable set, when request is getting data in response?
Thanks. The problem I encounter is somewhat different. I solved it with this code snippets … using async and await.
// request.js
const fetch = require('node-fetch')
async function myRequest (somestring) {
try {
let res = await fetch('https://api.domain.com/?endpoint='+somestring)
if (res.ok) {
if (res.ok) return res.json()
return new Error (res.status)
}
} catch (err) {
console.error('An error occurred', err)
}
}
module.exports = { myRequest }
// index.js
const request = require('./requests')
const myRequest = request.myRequest
let myVar;
myRequest('somestring')
.then(res => myVar = res.result)
setInterval(() => {
myRequest('somestring')
.then(res => myVar = res.result)
console.log(myVar)
}, 1000)
The async function and awaits return a promise. This promise is, when resolved, assigned to a variable.
This is my code:
const queryFirstNames = function (qString) {
let firstNameMatches;
client.query('SELECT * FROM famous_people WHERE first_name = $1', [qString], (err, result) => {
if (err) {
return console.error('error running query', err);
}
firstNameMatches = result.rows;
return firstNameMatches;
client.end();
});
};
console.log(queryFirstNames(qString));
});
This code return undefined and doesn't end the connection with the database
But if I console.log firstNameMatches inside the function instead of returning and then just invoke the function without console logging, I get the result I want, and the database connection closes properly.
What I want to do is return the result of this query and use it in another function, so I don't want it to console log the result, but when I try to return the result, it gives me undefined, and doesn't close the database connection either.
I believe that the issue you are having is that when you are returning firstNameMatches, you are returning it just to the callback for client.query. firstNameMatches is set inside of the context of the queryFirstNames function, however you never return that back. That being said, you are also utilizing an async call to client.query. This means that when you return from the queryFirstNames function, chances are you haven't finished querying. Per this, I am pretty sure you want to utilize promises to manage this or the events like one of the other answers.
In addition to this, you are going to want to move your return to before the client.end. To play with my answer, I created a jsfiddle that you can see here. I had to create my own promise via Promise just to mock out the client executing the query.
const queryFirstNames = function (qString) {
let firstNameMatches;
client.query('SELECT * FROM famous_people WHERE first_name = $1', [qString])
.then((result) => {
firstNameMatches = result.rows;
client.end();
return firstNameMatches;
})
.then(f => {
console.log(f);
})
.catch(e => {
if (err) {
return console.error('error running query', err);
}
});
};
You are returning the call before you even execute client.end(); This way your client connection will never end. You can do something like this:
const query = client.query(
'SELECT * FROM famous_people WHERE first_name = $1',
[qString],
(err, result) => {
if (err) {
return console.error('error running query', err);
}
});
query.on('row', (row) => {
results.push(row);
});
// After all data is returned, close connection and return results
query.on('end', () => {
return res.json(results);
});