check if for loop with mysql call inside is finished nodejs - javascript

so I have an array from another function that passes res which is a list looking like this:
[ RowDataPacket { UserID: 26 }, RowDataPacker { UserID: 4 } ]
it stores user id's, what I want is a function that finds the user id's username, and stores them in another array. This is what I have:
function getThem(res, params) {
var promises = res.map(function (item) { // return array of promises
// return the promise:
for (i = 0; i < Object.keys(res).length; i++) {
console.log("user: ", res[i].UserId);
getUsernameFromId(res[users.length].UserId).then(function() {
console.log("username: ", res[0].username);
users.push(res[0].username);
});
}
}, function (err) {
console.error(err);
});
Promise.all(promises).then(function () {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}
output in console:
user: 26
user: 4
user: 26
user: 4
users: []
username: undefined
username: undefined
username: undefined
username: undefined
so how can I wait for the for loop to complete the mysql call? Maybe there is another way of doing this?
edit: don't mind the undefined usernames, it's easy to fix later. Just tell me how I can have those undefined inside an array

Assuming (have to assume, because your code seems to use res like a majick object that has everything you need before you do anything with it) the actual res looks like
[ { UserID: 26 }, { UserID: 4 } ]
and getUsernameFromId returns an object with a username property, like
{ username: 'blah', ...otherproperties }
getThem can be simply
function getThem(res, params) {
return Promise.all(res.map(({UserID}) => getUsernameFromId(UserId).then(({username}) => username)))
.then(users => {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}
or in "old school" javascript
function getThem(res, params) {
return Promise.all(res.map(function (_ref) {
var UserID = _ref.UserID;
return getUsernameFromId(UserId).then(function (_ref2) {
var username = _ref2.username;
return username;
});
})).then(function (users) {
console.log("users: ", users);
//do something with the finalized list of albums here
});
}

Related

Error in updating profile with image using mongoose and cloudinary

updateProfile: async function(req, res) {
try {
const update = req.body;
const id = req.params.id;
if (!req.files || Object.keys(req.files).length === 0) {
return res.status(400).send('No files were uploaded.');
}
const image = req.files.profileImage;
const cloudFile = await upload(image.tempFilePath);
const profileImage = cloudFile.url
console.log('Loging cloudfile', profileImage)
await User.updateOne(id, { update }, { profileImage }, { new: true },
function(err, doc) {
if (err) {
console.log(err)
}
if (doc) {
return res.status(200).send({ sucess: true, msg: 'Profile updated successful' })
}
});
} catch (error) {
res.status(500).json({ msg: error.message });
}
}
But I'm getting an error of "Callback must be a function, got [object Object]"
I have tried to $set: update and $set: profileImage but still not working.
So the image successful upload into the cloudinary but the update for mongoose is not working.
Upon brief research into the issue, I think you are feeding the arguments in wrong. Objects can be confusing but not to worry.
Your code is:
await User.updateOne(id, { update }, { profileImage }, { new: true }
However, I believe it should be something more like:
await User.updateOne({id: id}, { profileImagine: profileImage, new: true },
The API reference annotates use of the function as:
const filter = { name: 'John Doe' };
const update = { age: 30 };
const oldDocument = await User.updateOne(filter, update);
oldDocument.n; // Number of documents matched
oldDocument.nModified; // Number of documents modified

How to architect array of promises in GraphQL resolver with multiple API calls to return a single object type list

I'm stuck in my GraphQL resolver fetching todo-lists for a particular user belonging to a company. According to whether or not they have access to all todo-lists or a certain few, it will fetch for groups the user registered to that have belonging todo-lists, and those should be fetched.
The code so far is capable of logging the requested todo-lists on the query but I have yet to come to the solution on how to actually return data of all of the user's registered groups's todo-lists.
I chose to export the actual logic into a separate function
The Resolver:
allowedListItems: {
type: new GraphQLList(TodoItem),
resolve(parentValue, args) {
return Promise.all([fetchAllowedItems(parentValue._id)]);
}
},
The Promise Function
function fetchAllowedItems(userId) {
return User.findOne({ _id: userId }).then((user) => {
if (user.todoGroups) {
return user.todoGroups.map((groupId) => {
return TodoGroup.findOne({ _id: groupId }).then(group => {
return group.todoLists.map((listId) => {
return TodoList.findOne({ _id: listId })
})
})
})
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
})
}
I am not getting any errors from GraphQL so I guess it's about the way I make the promisses return to the resolver, I'd appreciate a lot if you can help me out!
Update:
I should wrap the maps with a Promise.all, as the mapping returns an array.
Though the updated code brings no improvement in the returned data.
async resolve(parentValue, args) {
let user = await User.findOne({ _id: parentValue._id })
if (user.todoGroups) {
return Promise.all(user.todoGroups.map((groupId) => {
return TodoGroup.findOne({ _id: groupId }).then(group => {
return Promise.all(group.todoLists.map((listId) => {
return TodoList.findOne({ _id: listId });
}))
})
}))
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
}
},
Current query result:
{
"data": {
"user": {
"_id": "5ba11690ad7a93d2b34d21a9",
"allowedTodos": [
{
"_id": null,
"title": null
}
]
}
}
}
You need to call Promise.all on an array of promises, not a promise for that. Also you'll have to call it on each level:
allowedListItems: {
type: new GraphQLList(TodoItem),
resolve(parentValue, args) {
return User.findOne({ _id: parentValue._id }).then(user => {
if (user.todoGroups) {
return Promise.all(user.todoGroups.map(groupId => {
// ^^^^^^^^^^^^
return TodoGroup.findOne({ _id: groupId }).then(group => {
return Promise.all(group.todoLists.map(listId => {
// ^^^^^^^^^^^^
return TodoList.findOne({ _id: listId })
}));
});
}));
} else {
return TodoList.find({ company: parentValue.company }).exec();
}
});
}
}

Using async.js for deep populating sails.js

I have a big issue with my function in sails.js (v12). I'm trying to get all userDetail using async (v2.3) for deep populating my user info:
UserController.js:
userDetail: function (req, res) {
var currentUserID = authToken.getUserIDFromToken(req);
async.auto({
//Find the User
user: function (cb) {
User
.findOne({ id: req.params.id })
.populate('userFollowing')
.populate('userFollower')
.populate('trips', { sort: 'createdAt DESC' })
.exec(function (err, foundedUser) {
if (err) {
return res.negotiate(err);
}
if (!foundedUser) {
return res.badRequest();
}
// console.log('foundedUser :', foundedUser);
cb(null, foundedUser);
});
},
//Find me
me: function (cb) {
User
.findOne({ id: currentUserID })
.populate('myLikedTrips')
.populate('userFollowing')
.exec(function (err, user) {
var likedTripIDs = _.pluck(user.myLikedTrips, 'id');
var followingUserIDs = _.pluck(user.userFollowing, 'id');
cb(null, { likedTripIDs, followingUserIDs });
});
},
populatedTrip: ['user', function (results, cb) {
Trip.find({ id: _.pluck(results.user.trips, 'id') })
.populate('comments')
.populate('likes')
.exec(function (err, tripsResults) {
if (err) {
return res.negotiate(err);
}
if (!tripsResults) {
return res.badRequest();
}
cb(null, _.indexBy(tripsResults, 'id'));
});
}],
isLiked: ['populatedTrip', 'me', 'user', function (results, cb) {
var me = results.me;
async.map(results.user.trips, function (trip, callback) {
trip = results.populatedTrip[trip.id];
if (_.contains(me.likedTripIDs, trip.id)) {
trip.hasLiked = true;
} else {
trip.hasLiked = false;
}
callback(null, trip);
}, function (err, isLikedTrip) {
if (err) {
return res.negotiate(err);
}
cb(null, isLikedTrip);
});
}]
},
function finish(err, data) {
if (err) {
console.log('err = ', err);
return res.serverError(err);
}
var userFinal = data.user;
//userFinal.trips = data.isLiked;
userFinal.trips = "test";
return res.json(userFinal);
}
);
},
I tried almost everthing to get this fix but nothing is working...
I am able to get my array of trips(data.isLiked) but I couldn't get my userFInal trips.
I try to set string value on the userFinal.trips:
JSON response
{
"trips": [], // <-- my pb is here !!
"userFollower": [
{
"user": "5777fce1eeef472a1d69bafb",
"follower": "57e44a8997974abc646b29ca",
"id": "57efa5cf605b94666aca0f11"
}
],
"userFollowing": [
{
"user": "57e44a8997974abc646b29ca",
"follower": "5777fce1eeef472a1d69bafb",
"id": "5882099b9c0c9543706d74f6"
}
],
"email": "test2#test.com",
"userName": "dany",
"isPrivate": false,
"bio": "Hello",
"id": "5777fce1eeef472a1d69bafb"
}
Question
How should I do to get my array of trips (isLiked) paste to my user trips array?
Why my results is not what I'm expecting to have?
Thank you for your answers.
Use .toJSON() before overwriting any association in model.
Otherwise default toJSON implementation overrides any changes made to model associated data.
var userFinal = data.user.toJSON(); // Use of toJSON
userFinal.trips = data.isLiked;
return res.json(userFinal);
On another note, use JS .map or _.map in place of async.map as there is not asynchronous operation in inside function. Otherwise you may face RangeError: Maximum call stack size exceeded issue.
Also, it might be better to return any response from final callback only. (Remove res.negotiate, res.badRequest from async.auto's first argument). It allows to make response method terminal

Mongoose inside a promise change happens late

I am writing an API in NodeJS in which I use Mongoose and BlueBird. Regarding promise chain, my data was supposed to go through waterfall functions but it didn't. Let my example start with getTagNames to get some JSON , feeding data to retrieveTag to query and end up with res.json().
exports.getTagValues = function (req, res) {
var userId = req.params.uid;
getTagNames(req, res)
.then(retrieveTag)
.then(function (data) {
console.log('tags', data);
res.json(200, data);
})
.catch(function(err){
console.log('err', err);
//handle Error
})
}
Here is my toy data,
function getTagNames(req, res) {
var userId = req.params.uid;
return new Promise.resolve({
'userId': userId,
'variables': [
{ id: 1, name: 'hotel', type: 'String' },
{ id: 2, name: 'location', type: 'String' }
],
})
}
The way I query data. After querying inside mongo, I check whether or not have a document with userID. In case not, insert and return document. Note Tag is my mongo model
function retrieveTag(data){
Tag.findOne({'userId': data.userId})
.exec()
.then( function(tag){
if (tag) {
console.log('result', tag);
// do something ...
return tag;
}
else {
var newTag = new Tag({
advertiserId: advertiserId,
variables: variables
});
newTag.save()
.then(function () {
console.log('newTag', newTag);
return newTag;
});
}
})
}
Here is my result (userId is 1), my expectation is console.log('tags', data); occurs after all then data should not be undefined
tags undefined
GET /api/tag/values/1 200 3ms
newTag { __v: 0,
userId: '1',
_id: 581b96090e5916cf3f5112fe,
variables:
[ { type: 'String', name: 'hotel', id: 1 },
{ type: 'String', name: 'location', id: 2 } ] }
My question is how can I fix it. If there's some unclear, please help me correct.
The explanation is a bit unclear, but if I follow you right you loose data in the promise resolvement chain.
When reading your code, I notice that retrieveTag does not return the Mongoose promise. To let .then in getTagValues use the data found in retrieveTag.
So change to this:
function retrieveTag(data){
return Tag.findOne({'userId': data.userId})
.exec()
.then( function(tag){
...
})
}

Sequelize: Issue with join table and querying for results

Problem exists in the INDEX function, on var friends. I want to set it to an empty array initially so that I can push individual user objects from a friendship join table of users to said array. This is because the signed in user could exist on the friendship join table under the userID column or the friendID column, depending on who initiated the friendship.
The problem is due to the async nature, when I call console.log(friends) the querying of the database is milliseconds behind, so it is still logging an empty array. I want the array to be full of user objects who are *NOT the current user, which in essence would be a "myfriends" index page serving up JSON from the backend API. Keep in mind the fact I'm trying to serve Json, so all the friend user objects HAVE to end up in one single array.
Thanks!
var user = require("../../models/index").user;
var friendship = require("../../models/index").friendship;
var friendshipController = {
index: function(req, res) {
var friends = [];
var request = friendship.findAll({
where: {
status: "pending",
$and: {
$or: [
{
userId: req.session.user.id
},
{
friendId: req.session.user.id
}
]
}
}
}).then(function(friendships) {
res.json(friendships)
var friends = []
friendships.forEach(function(friendship) {
if (req.session.user.id === friendship.userId) {
user.findById(friendship.friendId).then(function(user) {
friends.push(user);
})
} else {
user.findById(friendship.userId).then(function(user) {
friends.push(user);
})
}
})
console.log(friends);
})
},
create: function(req, res) {
friendship.create({
userId: req.session.user.id,
friendId: 3,
}).then(function() {
res.redirect("/")
})
},
destroy: function(req, res) {
friendship.findAll().then(function(f) {
f.forEach(function(fn) {
fn.destroy()
})
})
}
}
module.exports = friendshipController;
SOLUTION: For each friendship, push each adjacent friend's id of the logged in user to an array...THEN run a query to find all users in that array (a feature of sequelize apparently), then respond with that json data.
index: function(req, res) {
var friends = [];
var query = friendship.findAll({
where: {
status: "pending",
$and: {
$or: [
{
userId: req.session.user.id
},
{
friendId: req.session.user.id
}
]
}
}
}).then(function(friendships) {
var friendIds = [];
friendships.forEach(function(friendship) {
if (req.session.user.id === friendship.userId) {
friendIds.push(friendship.friendId);
}
else {
friendIds.push(friendship.userId);
}
});
user.findAll({
where: {
id: friendIds
}
}).then(function(users) {
res.json(users);
})
})
}

Categories

Resources