Why does my recieved from database data is undefined? - node.js

I`m creating API on my express.js server, so when it takes "get" request, some function placed in module file asking data from graph db:
module.js file:
function getGraphData() {
const cityName = 'Milan';
const readQuery = `MATCH (City {name: $cityName})-[:LINKED*1..3]-(city:City) RETURN city`;
const cities = [];
session
.run(readQuery, { cityName })
.then(function (result) {
result.records.forEach(function (record) {
cities.push({
title: record._fields[0].properties.name,
});
});
return cities;
})
.catch((err) => console.log(err));
}
module.exports.getGraphData = getGraphData;
After receiving data it stores in array named cities and looks like this:
cities: [ { title: 'City1' }, { title: 'City2' }, { title: 'City3' } ]
So, function is returning this array, and then I import function from module and use it in my router file:
const { getGraphData } = require('./../db/neo4j');
router.get('/', async (req, res) => {
try {
const p = await getGraphData();
console.log('p:', p); //p is undefined
//return res.status(200).send(p);
return res.status(206).json(p); // empty response, not any data only status code
} catch (e) {
console.log(e);
});
So, what I'm doing wrong? Why does api response is empty?
Im use debugger. Data realy comes to function in module, but doesn`t passing to api response to "p" variable.

Your getGraphData function is using .then . When it executes it makes the session call and returns immediately that is why it returns empty.
Although, you are doing await on getGraphData, your getGraphData function needs to be defined as async and use await with session for it to work.
async function getGraphData() {
const cityName = 'Milan';
const readQuery = `MATCH (City {name: $cityName})-[:LINKED*1..3]-(city:City) RETURN city`;
const cities = [];
try{
const result = await session.run(readQuery, { cityName });
result.records.forEach(function (record) {
cities.push({
title: record._fields[0].properties.name,
});
});
return cities;
}
catch(err){
console.log(err);
return err;
}
}

Related

Nodejs exports returns undefined on mongoose Insertion

I have created nodejs application by organising as module structure , The problem I am facing is that a mongodb insertion return undefined value from one of my controller, The issue I found is that my async funtion doesn't wait to complete my mongodb operation But I could not find a solution for that, my route and controller code is given below
route.js
const {
createEvent, editEvent
} = require('./controller');
router.post("/event/create", validateEventManage, isRequestValidated, async(req, res) => {
let data = {};
data.body = req.body;
try{
let event = await createEvent(req.body);
console.log(event) // returned undefined
data.event = event;
res.status(200).json(data);
}catch(error){
console.log(error)
res.status(200).json({error:error});
}
});
controller.js
exports.createEvent = async(data) => {
// return "test" // This works correctly
const eventObj = {
name : data.name,
description : data.desc,
type : data.type,
startDate : new Date()
}
const event = await new Event(eventObj);
await event.save((error,event)=>{
if(error) {
return error;
}
if(event){
return event;
}
});
}
You should not await the new Event constructor.
Also, since you are using async - await you can
remove the callback from the save and try ... catch the error to handle it:
exports.createEvent = async (data) => {
// return "test" // This works correctly
const eventObj = {
name: data.name,
description: data.desc,
type: data.type,
startDate: new Date(),
};
try {
const event = new Event(eventObj);
await event.save();
return event;
} catch (error) {
return error;
}
};

Save in mongodb and pass created object to a function

I'm beginner at programing and I don't know how can I do something with the mongoose save result.
In my post endpoint I would like to not save and directly return but instead of it I would like to do something with the result of save method like take the _id value of the new object created and pass to a function.
Here's what my post endpoint is doing and I would like to after saving not return but instead call a function passing the checkout object created:
router.post('/', async function(req, res) {
const { checkinId, eventId, email } = req.body;
let CheckoutTest = {
checkinId: checkinId,
eventId: eventId,
email: email,
}
const newCheckout = new Checkout(CheckoutTest);
await newCheckout.save((err, checkout) => {
if(err) {
return res.status(400)
.send(err);
}else {
return res.status(200)
.json({message: "Checkout successfully added!", checkout});
}
})
});
An elegant way to do this would be to add a try...catch block
router.post('/', async function(req, res) {
const { checkinId, eventId, email } = req.body;
let CheckoutTest = {
checkinId: checkinId,
eventId: eventId,
email: email,
}
const newCheckout = new Checkout(CheckoutTest);
try {
const newCheckoutObject = await newCheckout.save()
// Call the function that you wanted to after the save.
// You can pass in the "_id" of the object as shown here
const newData = await functionToBeCalled(newCheckoutObject._id)
return res.status(200).json({message: "Checkout successfully added!", newData});
} catch (err) {
return res.status(400).send(err);
}
}

Async/await func in another async/await func in Node.js, MongoDB

I am trying to search available objects of a MongoDB collection(e.g. ParkingSpot) using specific business logic, the problem is that inside this function which is an async/await func I am looking inside another collection with .find() which I use as an async/await as well. The second function doesn't execute and gets back as an promise " Promise { } " and therefore the business logic is not applied. Can you help me please?
Here is 1st function:
exports.get_parkingSpots_avail_for_parking = async (req, res, next) => {
try {
const radius = req.body.radius;
const userLatitude = req.body.userLatitude;
const userLongitude = req.body.userLongitude;
const reqStartDate = new Date(req.body.reqStartDate);
const reqEndDate = new Date(req.body.reqEndDate);
const parkingSpots = await ParkingSpot.find({
isAvailable: true
}, (err, parkingSpots) => {
if (err) {
return res.status(500).json({
error: err
});
}
const freeParkingSpots = parkingSpots.filter(parkingSpot => {
return distanceCalculator(parkingSpot.latitude, parkingSpot.longitude, userLatitude, userLongitude) < radius
})
const availParkingSpots = freeParkingSpots.filter( freeParkingSpot => {
// console.log(freeParkingSpot._id);
console.log(isParkingAvailable(reqStartDate, reqEndDate, freeParkingSpot._id));
return isParkingAvailable(reqStartDate, reqEndDate, freeParkingSpot._id);
})
}).select('_id userId number address latitude longitude notes isAvailable startOfAvailability endOfAvailability');
console.log(parkingSpots);
if (parkingSpots.length > 0) {
return res.status(200).json({
parkingSpots: parkingSpots
});
}
return res.status(404).json({
message: "No available parking spots for requeste period"
});
} catch (err) {
res.status(500).json({
error: err
})
}
};
Second function which is being called :
module.exports = async function isParkingAvailable(reqStartDate, reqEndDate, parkingSpotId) {
const parkingSpotBookings = await Booking.find({ parkingSpotId: parkingSpotId})
.select('_id parkingSpotId sharerUserId renterUserId startDate endDate');
if (parkingSpotBookings.length == 0) {
return true;
}
parkingSpotBookings.filter(booking => {
//console.log(parkingSpotId);
//console.log("Is overlapping" +!isOverlapping(reqStartDate, reqEndDate, booking.startDate, booking.endDate));
return !isOverlapping(reqStartDate, reqEndDate, booking.startDate, booking.endDate)
})
}
So the problem is that calling second function appears as that in console.log :Promise { }
Await will Return the result to your parkingSpot variable.
For the second function:
You have defined this function as an async, that means it is holding asynchronous process, and in Node JS es6 async process is processed as a promise, so if you won't call it with await it will return a promise only
exports.get_parkingSpots_avail_for_parking = async (req, res, next) => {
try {
const radius = req.body.radius;
const userLatitude = req.body.userLatitude;
const userLongitude = req.body.userLongitude;
const reqStartDate = new Date(req.body.reqStartDate);
const reqEndDate = new Date(req.body.reqEndDate);
const parkingSpots = await ParkingSpot.find({isAvailable: true}).select('_id userId number address latitude longitude notes isAvailable startOfAvailability endOfAvailability');
const freeParkingSpots = parkingSpots.filter(parkingSpot => {
return distanceCalculator(parkingSpot.latitude, parkingSpot.longitude, userLatitude, userLongitude) < radius
});
const availParkingSpots = freeParkingSpots.filter( async freeParkingSpot => {
/* You have defined this function as an async, that means it is holding asynchronous process, and in
Node JS es6 async process is processed as a promise, so if you won't call it with await it will return a promise only */
return await isParkingAvailable(reqStartDate, reqEndDate, freeParkingSpot._id);
});
if (parkingSpots.length > 0) {
return res.status(200).json({
parkingSpots: parkingSpots
});
}
return res.status(404).json({
message: "No available parking spots for requeste period"
});
} catch (err) {
res.status(500).json({
error: err
})
}
};
I hope it will help you.
Thank you

Nodejs wait for query

I'm using Nodejs with MongoDB(mongoose along with express).
Since I don't trust the user data, I need to verify it from the database.
input data:
{
"id": "someid",
"nottrusteddata": [ {"id": "1"}, {"id" :"2"}]
}
In my function, I'm verifying the data:
router.post("/validate", (req, res,next) =>{
let validated_data = validate_data(req);
console.log(JSON.stringify(validated_data));
const mydata = new Mydata({
id: req.body.id,
lst : validated_data
});
console.log("mydata: " + JSON.stringify(mydata));
/* Some Usefull stuff is here */
res.status(200).json();
}
function validate_data(req){
let validated_data = []
for(let i = 0; i < req.body.nottrusteddata.length; i++)
{
Databaseobject.findOne({'id': req.body.nottrusteddata[i].id})
.exec()
.then(dbobject =>{
if(dbobject) // not undefined, it exists in the database
{
// Some logic with the object returned from the database
let tmp_object = {};
tmpobject.id = dbobject.id;
// Append it to the list, so that the upper function can use it
validated_data.push(tmp_object);
}
})
}
return validated_data;
}
The desired output should contain the correct information coming from the database, however, due to the async nature of the nodejs, validated_data returns null.
I have also tried using Promise. I couldn't succeed it.
const validate_data = function(req){
return new Promise(function(resolve,reject){
let validated_data = []
for(let i = 0; i < req.body.nottrusteddata.length; i++)
{
Databaseobject.findOne({'id': req.body.nottrusteddata[i].id})
.exec()
.then(dbobject =>{
if(dbobject) // not undefined, it exists in the database
{
let tmp_object = {};
tmpobject.id = dbobject.id;
validated_data.push(tmp_object);
}
})
}
resolve(validated_data);
}
}
What am I doing wrong? How can I wait for the database query to finish, then execute the main part? If there is only one validation, I could've used .then(). However, the list might have contained many elements and I need to wait for all of them to be verified.
Your Databaseobject.findOne() calls are asynchronous so your promise will resolve before any of them complete.
You can make use of Promise.all to wait until all of your promises resolve.
Hopefully, this will work for you:
router.post("/validate", (req, res) => {
validate_data(req.body.nottrusteddata)
.then(validated_data => {
const mydata = new Mydata({
id: req.body.id,
lst: validated_data
})
// Some useful stuff is here
res.status(200).json()
})
.catch(err => {
// Handle error
})
}
function validate_data(nottrusteddata) {
// Create array of pending promises
const promises = nottrusteddata
.map(item => {
return Databaseobject
.findOne({ 'id': item.id })
.exec()
})
// Wait for all promises to resolve
return Promise.all(promises)
.then(docs => {
return docs
.filter(dbobject => dbobject) // Filter out undefined
.map(dbobject => {
return { id: dbobject.id }
})
})
}
If you want, you could also use async-await here:
router.post("/validate", async (req, res) => {
try {
const validated_data = await validate_data(req.body.nottrusteddata)
const mydata = new Mydata({
id: req.body.id,
lst: validated_data
})
// Some useful stuff is here
res.status(200).json()
}
catch(err) {
// Handle error
}
})

passing json formatted with information from multiple json documents nodeJs

I have a function where I would like to return an arrays of JSON objects with the necessary information. to send directly to the front everything ready.
async listProcessByOffice(req, res, next) {
try {
const actualPlayer = await PlayerOffice.findById(req.userId);
const actualOffice = await Office.findById(actualPlayer.Office);
const listProcesses = await Processes.find({ '_id': { $in: actualOffice.processes } });
const infosTable = {
protocol: ''
};
for (let i in listProcesses) {
this.protocol = listProcesses[i].prc_protocol;
console.log(this.protocol)
}
return res.status(200).json({ infosTable });
} catch (err) {
return next(err);
}
Not sure what you are looking for but i am assuming that you want to response back with array list of objects. So simple answer will be,
const infosTable = [];
for (let i in listProcesses) {
this.protocol = listProcesses[i].prc_protocol;
infosTable.push({protocol:listProcesses[i].prc_protocol})
console.log(this.protocol)
}

Resources