return multiple queries from backend - node.js

Straight forward: I have a backend with multiple routes.
Is it possible to return multiple queries from one route, e.g.:
router.get("/test/:id", (req, res) => {
example.find({test: req.params.id})
.then(data => res.json(data.map(moreData => moreData.serialize()))
differentExample.find({something: req.params.id})
.then(data => res.json(data.map(moreData => moreData.serialize()))
})
And then have both finds/results in the front-end:
.then(res => {
if (!res.ok) {
return Promise.reject(res.statusText);
}
return res.json();
})
.then(data => console.log(data))
I found that if I user Promise.all() I use the result of the first query for the query parameters of the second. The above is just my thought process. It doesn't work like this and I am missing the piece that makes it happen (if it's possible)

You can't send multiple responses using HTTP. HTTP requests to responses are 1:1 so when a request is sent you will ALWAYS expect only one response. Anything else and it would get quickly messy. So, how to send multiple sets of data?
You could do something like this:
router.get("/test/:id", (req, res) => {
let result = {}
example.find({test: req.params.id})
.then(data => {
result['partOne'] = data.map(moreData => moreData.serialize())
return differentExample.find({something: req.params.id})
}).then(data => {
result['partTwo'] = data.map(moreData => moreData.serialize())
res.json(result)
})
}
Note: I haven't tested any of this code. But in essence, do both requests, and once you have the result of both requests you can return the result. If the requests don't depend on each other, you could use something like this using Promise.all as you mentioned:
Promise.all(
example.find({test: req.params.id},
differentExample.find({something: req.params.id})
).then(result => {
res.json(result);
})

Related

axios__WEBPACK_IMPORTED_MODULE_1___default(...).delete(...).then(...).error is not a function

I want to delete product detail #
Below API is used to call the node.js API ##
When a button is pressed then deleteApi is called then this will be matched with the backend
const deleteApi = (id) => {
console.log(id);
axios
.delete(`http://localhost:5000/delete-list/${id}`)
.then((res) => {
console.log("Deleted Iteam", res);
})
.error((error) => {
console.log(error);
});
};
The problem here is that you need to use .catch instead of .error, change it.

How to access data passed from dyamic route from express.js to react.js

Here is my backend route, i'm getting a file name as parameter from URL and accessing the file. how do I access the data passed from this route into my frontend react.js??
router.route("/list/:filename").get((req, res) => {
fs.readFile("./api/assignment_data/" + req.params.filename + ".json", function read(err, data) {
if (err) {
throw err;
}
const content = data;
foundFile => res.json(foundFile)
console.log("sent")
})
})
In my frontend I am doing something like this,
useEffect(() => {
fetch("/list/:filename").then(res => {
if (res.ok) {
console.log("all ok")
return res.json()
}
}).then(jsonRes => setMetrics(jsonRes))
})
I think you are doing everything right as long as you are sending correct file name which in react you have marked as :filename(like data.json) if you are doing that it should work, I just dont understand this line foundFile => res.json(foundFile) because you are not sending any file in return maybe you can try replacing that line with res.status(200).json({data}); this should work
You are using useeffect wrong this way it will infinitely run rerendering your application everytime there is any change in DOM, so do this
useEffect(() => {
fetch("/list/:filename").then(res => {
if (res.ok) {
console.log("all ok")
return res.json()
}
}).then(jsonRes => setMetrics(jsonRes))
},[])
this way it'll only run once

Express returns empty array

I currently have the following code
router.get('/uri', (request,response) => {
let final = [];
TP.find({userID: request.userID})
.then(tests =>{
tests.forEach(test => {
A.findById(test.assignmentID)
.then(assignment => {
final.push({
testID: test._id,
name: assignment.title,
successRate: `${test.passedTests}/${test.totalTests}`
})
})
.catch(error => {
console.log(error)
})
})
return response.send(final);
})
.catch(err => {
console.log(err);
return response.sendStatus(500);
})
})
The code is supposed to query 2 MongoDB databases and construct an array of objects with specific information which will be sent to the client.
However, I always get an empty array when I call that endpoint.
I have tried making the functions async and make them wait for results of the nested functions but without success - still an empty array.
Any suggestions are appreciated!
forEach doesn't care about promises inside it. Either use for..of loop or change it to promise.all. The above code can be simplified as
router.get('/uri', async (request,response) => {
const tests = await TP.find({userID: request.userID});
const final = await Promise.all(tests.map(async test => {
const assignment = await A.findById(test.assignmentID);
return {
testID: test._id,
name: assignment.title,
successRate: `${test.passedTests}/${test.totalTests}`
};
}));
return response.send(final);
});
Hope this helps.

async task in node.js

I have four task that are working in sync.
It looks like this:
function createEntity(req, res, next) {
validator.validateInternalProductRequest(req.body)
.then((data) => feedbackSetting.getUrl(data))
.then((data) => bitlyService.shortenLink(data))
.then((data) => internalProductService.saveInternalProductRequest(data))
.then((data) => res.send(data))
.catch(err => {
console.log(err);
next(err)
});
}
Now between 3rd and 4th task, that is after getting short link and before saving to the database, I need to perform a task, lets say Task AS that I need to run asynchronously. The 4th task, i.e saving to the database should not be blocked because of this.
Now this task AS that I have to do asynchronously, has further three more task:
1. getting setting from db
2. making curl request
3. saving in the database
These three task I can do using async.waterfall or I am hoping there would be any alternatives to this?
How do I perform this task AS in the above mentioned function createEntity?
If you do not want to wait for the async task, just call it and dont wait for it. It is easy as that.
function createEntity(req, res, next) {
validator.validateInternalProductRequest(req.body)
.then((data) => feedbackSetting.getUrl(data))
.then((data) => {
callSomeAsyncMethodAndDontWaitForResult();
return bitlyService.shortenLink(data)
}).then((data) => internalProductService.saveInternalProductRequest(data))
.then((data) => res.send(data))
.catch(err => {
console.log(err);
next(err)
});
}

Nodejs loop through response data from request

The below data is returned from the request() library.
var data = [{
service: "trains",
...
}, {
service: "buses",
...
}]
I have the following code on a NodeJS application.
request(options)
.then(data => {
data.forEach(record => {
if (record.service !== 'buses') {
return next('You do not have permission to access buses.')
}
return next()
})
})
.catch(err => next(err))
So when this code runs on Node it always evaluates to false? This is odd to me because running this without the request and just using the raw response directly seems to work ok? I guess this is an issue with async behavior?
You're looping through all the elements of the array, so if the first element does not match 'buses', it will result in 'You do not have permission to acces buses'.
I think what you're looking for is a method to check if an element exists in an array. In your case something like Array.filter:
.then(data => {
if (data.filter(el => el.service === 'buses').length === 0) {
return next('You do not have permission to access buses.');
}
return next();
})

Resources