Promise resolves before loop completes in sails - javascript

I have a list of posts containing userId. When fetching n no.of post, I want to loop throught and get and fetch user data and append them into the post.
But before the loop gets resolved, the function gets return with undefined. After that, the post data gets listed but I want the post data to be fetched first.
I am new to promises and async. If there are any other solutions that I can use, then please notify me.
I am using sailsjs.
fetchPosts: async (req, res) => {
let feeds = [];
posts = await Posts.find({
skip: offset,
limit: limit,
sort: sort,
});
if (posts) {
/**
* LOOPING THROUGH FETCHED POST LOOP TO GET
* USER DATA, LIKE, SHARE, FOLLOW, BOOKMARKS
*/
const functionWithPromise = (post) => {
//a function that returns a promise
console.log(feeds);
return Promise.resolve(post);
};
const anotherAsyncFunction = async (post) => {
return functionWithPromise(post);
};
const getUser = async (userId, post) => {
return new Promise(async (resolve, reject) => {
const user = await Account.findOne({ id: userId });
if (user) {
post = {
...post,
user: {
id: user.id,
uName: user.uName,
provider: user.provider,
dpURL: user.dpURL,
provider: user.provider,
},
};
resolve(post);
} else {
reject(null);
}
});
};
const anAsyncFunction = async (post) => {
if (post.isAdminPost) {
post = {
...post,
user: {
id: "5f3b8bf00dc3f12414b7f773", // this is usedid of admin#dopaminetalks.com in `Admin` model
uName: "DTOfficial",
provider: "LOCAL",
dpURL: "/dpURL/86a73b80-babc-4caa-a84c-762f6e9c1b36.png",
},
};
feeds = [...feeds, post];
return anotherAsyncFunction(feeds);
} else {
getUser(post.userId, post).then((post) => {
feeds = [...feeds, post];
return anotherAsyncFunction(feeds);
});
}
};
const getData = async () => {
return Promise.all(posts.map((post) => anAsyncFunction(post)));
};
getData().then((data) => {
console.log(data);
return res.json({
status: true,
msg: "Posts Fetched",
data: data,
});
});
}
},

Related

Node Express app not getting data from Postgres table even with async await

So I'm trying to fetch a row from my Postgres db table by id. In the function that calls the query there is data, but in the controller I'm getting a null. Seems like the controller is resolving before my query, but not sure why since I have await. My code is as follows:
TripQuery.ts
const Pool = require('pg').Pool
const pool = new Pool({
user: process.env.PG_USER,
host: process.env.PG_HOST,
database: process.env.PG_DATABASE,
password: process.env.PG_PASSWORD,
port: process.env.PG_PORT,
})
const dbGetTripById = async (id: string) => {
try {
await pool.query('SELECT * FROM trips WHERE id = $1', [id], (error: Error, results: QueryResult) => {
if (error) {
throw error
}
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return trip
} else {
return null
}
})
} catch (e) {
console.log(e)
}
return null
}
TripController.ts
const getTrip = async (req: Request, res: Response) => {
const id = req.params.id
try {
const trip = await dbGetTripById(id)
console.log('from controller')
console.log(trip)
if (trip != null) {
res.status(200).json(trip)
} else {
res.status(404).send(`Trip with ID: ${id} does not exist`)
}
} catch (e) {
console.log(e)
}
}
TripRoutes.ts
import * as express from 'express'
import { addTrip, getTrips, getTrip, updateTrip } from '../controllers/TripController'
const router = express.Router()
router.get('/:id', getTrip)
export default router
When I call my endpoint http://localhost:3000/trips/123 I get the following logs:
Application is running on port 3000.
from controller
null
from db:
{ id: '123', userId: 'u123', name: 'trippy' }
And get the 404 error back even though the database query has fetched a value.
What am I doing wrong?
pool.query likely doesn't return a promise if a callback is passed.
Wrap it in a promise as:
const dbGetTripById = async (id: string) => {
return new Promise((resolve, reject) => {
pool.query('SELECT * FROM trips WHERE id = $1', [id], (error: Error, results: QueryResult) => {
if (error) {
return reject(error);
}
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return resolve(trip)
} else {
return reject(new Error("Record not found"))
}
})
})
}
Or use promise syntax:
const dbGetTripById = async (id: string) => {
await pool.query('SELECT * FROM trips WHERE id = $1', [id])
.then(results => {
if (results.rows.length > 0) {
const trip: Trip = {
id: results.rows[0].id,
userId: results.rows[0].user_id,
name: results.rows[0].name,
}
console.log('from db:')
console.log(trip)
return trip
} else {
throw new Error("No results")
}
})
}

Mapping data form database to an array of objects in JS

I have this code in App.js
const getPlayers = async()=>{
const players = await API.getPlayers();
setPlayers(players)
}
getPlayers()
This code in my API.js file
const getPlayers = async () => {
return getJson(
fetch(SERVER_URL + 'users', { credentials: 'include'})
).then( json => {
return json.map((user) => {
return {
id: user.id,
name: user.name,
rank: user.rank
}
})
})
}
This code in my server.js file
app.get('/api/players',
(req, res) => {
riddleDao.getPlayers()
.then(async players => {
res.json(players)
})
.catch((err) => res.status(500).json(err));
});
and finally, this in my DataAccessObject.js file
exports.getPlayers = () => {
return new Promise((resolve, reject) => {
const sql = 'SELECT * FROM users';
db.all(sql, [], (err, rows) => {
if (err) { reject(err); return; }
else {
const players = rows.map(row => {
return {
id: row.id,
name: row.name,
rank: row.rank
}
})
resolve(players);
}
});
});
};
but i am getting this error:
I am expecting to get an array of object in my App.js when i call the getPlayer() function and the objects in the array should have id, name and rank of the players in my db table
I think you've got "users" in your fetch URL when it should be "players".
fetch(SERVER_URL + 'users', { credentials: 'include'})
should be
fetch(SERVER_URL + 'players', { credentials: 'include'})
your api endpoint differs from the url you are sending requests
app.get('/api/players',
you are listening to "players" but
fetch(SERVER_URL + 'users', { credentials: 'include'})
you are fetching "users"

Async/Await : called function is not awiting and returning value

Hello I am creating 1 function with dynamic arguments where as I am calling api and on defined route I am calling express middleware function and from there I am calling another dynamic function which will help me to insert data into the database.
I am using Sequalize ORM
Here is code:
var async = require('async');
// Models
var LogSchema = require('../models/Logs')
module.exports = {
insertLog: async (req, res) => {
let result = await insertLogFn('1', 'method_name()', 'module_name_here', 'req.body', '{ api response }', 'action', '24')
console.log("result", result)
res.status(200).json(result)
}
};
function insertLogFn(status, invokedMethodName, moduleName, bodyRequest, apiResponse = null, actionName = null, userId) {
async.waterfall([
(nextCall) => {
let dataToBeInserted = {}
dataToBeInserted.status = status,
dataToBeInserted.invoked_method_name = invokedMethodName,
dataToBeInserted.module_name = moduleName,
dataToBeInserted.body_request = bodyRequest,
dataToBeInserted.api_response = apiResponse
dataToBeInserted.action_name = actionName,
dataToBeInserted.user_id = userId
LogSchema.create(dataToBeInserted).then(res => {
const dataObj = res.get({plain:true})
nextCall(null, {
status: 200,
message: "Log inserted successfully",
data: dataObj
})
}).catch(err => {
})
}
], (err, response) => {
if(err) {
}
return response
})
}
In module.export I have added insertLog function which is getting called in api and from there I am calling insertLogFn() which is declared outside of the module.export.
I am able to get inserted result in function insertLogFn() but the things is await is not working and not waiting for the result.
What I want to do is to wait till insertLogFn gets executed and the returned response has to be stored in the variable and return it as an api response.
You cannot. As per my understanding, IMO, Thumb rule is "Async/Await operation should return a promise"
function insertLogFn(status, invokedMethodName, moduleName, bodyRequest, apiResponse = null, actionName = null, userId) {
async.waterfall([
(nextCall) => {
let dataToBeInserted = {}
dataToBeInserted.status = status,
dataToBeInserted.invoked_method_name = invokedMethodName,
dataToBeInserted.module_name = moduleName,
dataToBeInserted.body_request = bodyRequest,
dataToBeInserted.api_response = apiResponse
dataToBeInserted.action_name = actionName,
dataToBeInserted.user_id = userId
LogSchema.create(dataToBeInserted).then(res => {
const dataObj = res.get({plain:true})
nextCall(null, {
status: 200,
message: "Log inserted successfully",
data: dataObj
})
return ;
console.log("you should return something here<-------");
}).catch(err => {
})
}
], (err, response) => {
if(err) {
}
return response
})
}
Now the answer will be clear if you read this one from Bergi: https://stackoverflow.com/a/40499150/9122159

How to use nextPageToken to retrieve contacts list from google api. Working example

I´m using this code to retrieve my contacts list inside a firebase function following the
(https://github.com/googleapis/google-api-nodejs-client/blob/master/samples/people/contacts.js) example
const { google } = require('googleapis');
const clientAuth = require('./clientAuth');
exports.getGoogleContacts = functions.https.onCall(async (data, context) => {
console.log('getGoogleContacts- init function')
const contacts = google.people({
version: 'v1',
auth: clientAuth.oAuth2Client,
});
return new Promise((resolve, reject) => {
clientAuth
.authenticate(['https://www.googleapis.com/auth/contacts'])
.then(async () => {
console.log('after client auth')
contacts.people.connections.list({
resourceName: "people/me",
pageSize:200,
personFields: ['addresses',
'ageRanges',
'biographies',
'birthdays',
'braggingRights',
'coverPhotos'], // ... and many other fields
}, function (err, response) {
if (err) {
console.log('contacts.people.connections error')
console.log(err)
reject(new Error(err))
} else if (response) {
console.log('contacts.people.connections response')
console.log(response)
if (response.pageToken) {
// how could I continue to retrieve next page of contacts?
}
resolve(response)
}
})
})
})
})
If there is a nextPageToken, there is no working example I´ve was able to found.
edited - this code was able to solve the pagination with array concatenation
I was able to come up with this solution, even though now I´m facing a problem of pushing to the connections array... It´s not working
const listOptions = {
resourceName: "people/me",
pageSize: 200,
personFields: ['addre...']
}
async function getConnectionsList(contacts, nextPageToken) {
if (!nextPageToken) {
return contacts.people.connections.list(listOptions)
} else {
listOptions.pageToken = nextPageToken
return contacts.people.connections.list(listOptions)
}
}
let response = await getConnectionsList(contacts)
let nextPage = response.data.nextPageToken
let connections = response.data.connections
while (nextPage) {
nextPage = await getConnectionsList(contacts, nextPage)
connections.push(nextPage.data.connections) // not working
connections.concat(nextPage.data.connections) // also not working...
nextPage = nextPage.data.nextPageToken
console.log('hasNextPage?', nextPage)
}
console.log('connections',connections)
resolve(connections)

Node.js, RESTIFY, Mongoose, Promise: Trying to $push an array to update but not working

I used this method because I am storing an array of classified messages, I would like to vividly understand why it doesn't update.
Here's the db.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = mongoose.Types.ObjectId;
const usersessionSchema = new Schema({
fb_id: String,
fb_name: String,
fb_profpic: String,
message_body: [
{
message: String,
message_type: String,
timestamp: String
}
],
admin: Boolean,
branch: String
});
const model = (prefix) => {
prefix = prefix || '';
console.log(prefix);
if (prefix.length > 0) {
return mongoose.model(prefix + "-usersessions", usersessionSchema);
} else {
return new Error('Undefined collection prefix!');
}
}
/** Push message into message body*/
module.exports.pushsession =
async(model, id, data) => {
return new Promise((resolve, reject) => {
console.log(data);
model.findOneAndUpdate({fb_id: id}, {$push: {data}},{safe: true})
.then(res => {
console.log(res);
/
resolve(res);
})
.catch(err => {
reject(err);
console.log(err);
throw err;
});
});
}
Here's the controller.js:
/** Push usersession message */
module.exports.pushsession =
async(req, res, next) => {
try {
//jwt.validateToken(req);
var en = "en";
var dateEn = moment().locale(en);
format = "MM/DD/YYYY h:mm:ss A"; //h:mm:ss.SSS if you want miliseconds
var datetime_now = dateEn.format(format);
console.log(datetime_now);
var request = {
message_body: {
message: req.body.message,
message_type: req.body.message_type,
timestamp: datetime_now
}
};
const model = usersessionDB(req.query['client']);
const id = req.body.fb_id;
const result = await usersessionDB.pushsession(model, id, request);
if (result) {
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
} else {
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
}
} catch (err) {
response.failure(res, next, err, 500, response.HTTP_STATUS_CODES.internal_server_error);
}
}
Here's the route.js:
const controller = require('../controller/usersession-controller');
module.exports =
(server) => {
server.post('/api/session', controller.create);
server.get('/api/session', controller.list);
server.get('/api/session/:id', controller.get);
server.put('/api/session/:id', controller.update);
server.del('/api/session/:id', controller.delete);
server.put('/api/pushsession', controller.pushsession);
}
Visually, if you run this using postman, you can see that it display the one I want to search and update
Result of the postman
What I want to happen is to insert another set of array inside that message_body
Data I've inserting
My desired output
This code is working without that promise something, but in my project it is needed so I can't remove that thing.
So, based on :
This code is working without that promise something
i can point a thing or two,
in db.js
module.exports.pushsession =
async(model, id, data) => {
return new Promise((resolve, reject) => {
you don't need async since you're returning a promise so replace this
async(model, id, data) => {
with
(model, id, data) => {
and since you're returning a promise and removed async , you don't need the await on the other side ( controller.js ), so this
const result = await usersessionDB.pushsession(model, id, request);
if (result) {
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
} else {
should be
usersessionDB.pushsession(model, id, request).then(
(result) => { // when resolved
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
},
(err) => { // when rejected
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
});
this is a comparison between async/await and promises : Javascript Promises vs Async Await. Difference?
and here's some good examples of using promises : https://medium.com/dev-bits/writing-neat-asynchronous-node-js-code-with-promises-32ed3a4fd098
i think your $push is ok but you already said
This code is working without that promise something
i hope this helps and Good luck :)
I tried cleaning my code
here's the controller.js:
/** Push usersession message */
module.exports.pushsession =
async (req, res, next) => {
try {
//jwt.validateToken(req);
var en = "en";
var dateEn = moment().locale(en);
format = "MM/DD/YYYY h:mm:ss A"; //h:mm:ss.SSS if you want miliseconds
var datetime_now = dateEn.format(format);
console.log(datetime_now);
var data = {
message: req.body.message,
message_type: req.body.message_type,
timestamp: datetime_now
};
const model = usersessionDB(req.query['client']);
const id = req.body.fb_id;
console.log(id);
const result = await usersessionDB.pushsession(model, id, data).then(
(result) => { // when resolved
response.success(res, next, result, 200, response.HTTP_STATUS_CODES.ok);
},
(err) => { // when rejected
response.failure(res, next, {
message: 'ID does not exist'
}, 404, response.HTTP_STATUS_CODES.not_found);
});
} catch (err) {
response.failure(res, next, err, 500, response.HTTP_STATUS_CODES.internal_server_error);
}
}
Here's the db.js:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const ObjectId = mongoose.Types.ObjectId;
const usersessionSchema = new Schema({
fb_id: String,
fb_name: String,
fb_profpic: String,
message_body:[{
message: String,
message_type: String,
timestamp: String
}],
admin: Boolean,
branch: String
});
/** Push message into message body*/
module.exports.pushsession =
async(model, id, data) => {
console.log(data);
return new Promise((resolve, reject) => {
model.findOneAndUpdate({fb_id: id}, { $push: { message_body: data }})
.then(res => {
console.log(res);
resolve(res);
})
.catch(err => {
reject(err);
console.log(err);
throw err;
});
});
}
Out of the blue after I tried to replace $push with $set then again I replace it with $push, it worked.
I don't if there's a difference, or I miss something, feel free to point it out.

Categories