Sequelize: Issue with join table and querying for results - javascript

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);
})
})
}

Related

mongodb having multiple conditions for $nin and data coming from the client

I'm trying to do a query based on some data but apparently, $nin is not reading the returned values from the function.
My goal is to not show all the users I've followed on the recommended section where there is a get request to receive all the users registered on the db.
I do have the following users on the function, however when I try to do the query, its not working and I've tried for hours fixing that problem.
At username: { $nin: [allFollowers.forEach((following) => following.username)] => Doing this, doesnt work, however when I put strings from the list of following users such as 'user1', 'user2', it works. My api updates on the client and I dont see those two users I follow on the recommended section.
I'd appreciate if you could help me.
exports.recommendedUsers = async function (req, res) {
// all following users in an array
const { followingUsers } = req.body;
/* console.log(followingUsers) =>
[
{
username: 'user1',
avatar: '//www.gravatar.com/avatar/c76fa83b3saddasdas2c04a59d6e063918badbf53?s=200&r=pg&d=mm'
},
{
username: 'user2',
avatar: '//www.gravatar.com/avatar/3758e369b058b393541asdasda4d0e8a1d57402?s=200&r=pg&d=mm'
},
{
username: 'uiser3',
avatar: 'https://static-cdn.jtvnw.net/jtv_user_pictures/bobross-profile_image-0b9dd16cascad7a9bb16b5-70x70.jpeg'
},
{
username: 'user4',
avatar: 'https://static-cdn.jtvnw.net/jtv_user_pictures/82b63a01-628f-4c81-9b05-dd3a501asdasd1fdda-profile_image-70x70.png'
},
{
username: 'user5',
avatar: '//www.gravatar.com/avatar/93cd495a412a1b2asdadabe9b9c72bc246e271?s=200&r=pg&d=mm'
}
] */
let allFollowers = [];
let following = req.body.followingUsers.forEach((follow) =>
allFollowers.push(JSON.stringify(follow.username))
);
console.log(`this is all followers: ${allFollowers}`);
try {
const user = User.find(
{
_id: { $ne: req.user.id },
username: {
$nin: [allFollowers.forEach((following) => following.username)], // not working
},
},
function (err, users) {
let userMap = {};
users.forEach(function (user) {
userMap[user._id] = user;
});
const arrayData = Object.values(userMap);
return res.json(arrayData);
}
).select('-password');
} catch (e) {
console.log(e.message);
}
};
You are using foreach function, that is wrong:
username: {
$nin: [allFollowers.forEach((following) => following.username)],
}
The return value of foreach is undefined, use map function.
try {
const user = User.find(
{
_id: { $ne: req.user.id },
username: {
$nin: allFollowers.map((following) => following.username),
},
},
function (err, users) {
let userMap = {};
users.forEach(function (user) {
userMap[user._id] = user;
});
const arrayData = Object.values(userMap);
return res.json(arrayData);
}
).select('-password');
} catch (e) {
console.log(e.message);
}

How to filter data from mongo collection subarray with subarray data of other collection

Baiscally making a node.js, mongodb add friends functionality where having the option of list user to add in friends list, sent friends request, accept friends request, delete friends request, block friends request.
Register Collection
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let Register = new Schema(
First_Name:{
type: String,
required: true
},
Last_Name: {
type: String
},
Email: {
type: String,
unique: true,
lowercase: true,
required: true
},
Friends:[{type: String}],
});
module.exports = mongoose.model('Register', Register);
Friends Collection
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
var ObjectId = require('mongodb').ObjectID;
let Friends = new Schema({
Requester: {
type: ObjectId,
required: true
},
Recipients: [{Recipient:{type:ObjectId},Status:{type:Number}}],
});
module.exports = mongoose.model('Friends', Friends);
Inside Node.js Post API
var Register = require('../models/register.model');
var Friends =require('../models/friends.model');
router.post('/getdata',function(req,res)
{
let Email="example#example.com";
Register.findOne({ Email : Emails }, function(err, user) {
Friends.findOne({ Requester :user._id }, function(err, user1) {
Register.find({$and:[{Friends:{$nin:[user._id]}},{_id:{$ne:user1.Recipients.Recipient}}]},function(err, user2) {
console.log("user2",user2);
//Here User2 data is not coming
//How to get data so can able to list user that is not added yet in FriendList
//Mainly user1.Recipients.Recipient this is not working because //Recipients is array so how can match all data with array, if i am //using loop then find return data scope ends on inside find closing //braces only.
//Any suggestion
});
});
});
So if I have it correct, you want to do the following:
Find a registration based on a given email
Find the friends related to this user
Find registrations that are not yet in the friend list of the user
Also, given what you've typed, I'm assuming A can be the friend of B, but that doesn't mean B is the friend of A.
While the data structure you currently have may not be optimal for this, I'll show you the proper queries for this:
var Register = require('../models/register.model');
var Friends =require('../models/friends.model');
router.post('/getdata',function(req,res) {
const email = "example#example.com";
Register.findOne({ Email: email }, function(err, user) {
if (err) {
console.error(err);
return;
}
Friends.findOne({ Requester: user._id }, function(err, friend) {
if (err) {
console.error(err);
return;
}
const reciptientIds = friend.Recipients.map(function (recipient) {
return recipient.Recipient.toString();
});
Register.find({Friends: { $ne: user._id }, {_id: { $nin: recipientIds }}, function(err, notFriendedUsers) {
if (err) {
console.error(err);
return;
}
console.log(notFriendedUsers);
});
});
});
});
P.S. This "callback hell" can be easily reduced using promises or await/defer
Finally able to solve it, below is the solution
var Register = require('../models/register.model');
var Friends =require('../models/friends.model');
router.post('/getdata',function(req,res)
{
let Emails="example#example.com";
Register.findOne({$and:[{ Email : Emails}] }, function(err, user) {
if (err) {
console.error(err);
return;
}
Friends
.findOne({ Requester: user._id },
{ _id: 0} )
.sort({ Recipients: 1 })
.select( 'Recipients' )
.exec(function(err, docs){
docs = docs.Recipients.map(function(doc) {
return doc.Recipient; });
if(err){
res.json(err)
} else {
console.log(docs,"docs");
Register.find({$and:[{Friends: { $ne: user._id }},{_id: { $nin: docs }},{_id:{$ne:user._id}}]}, function(err, notFriendedUsers) {
if (err) {
console.error(err);
return;
}
console.log(notFriendedUsers);
});
}
})
});

check if for loop with mysql call inside is finished nodejs

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
});
}

Populate nested collections with Sails Js and async

Im trying to query a deep association using sails js. In my example i have a one to many association between room and users and also a one to many association between user and pictures. My concern is if this is the correct way to assign pictures to users and also how can i map each collection of pictures to the corresponding user. Thanks.
// RoomController
show: function(req, res) {
async.auto({
room: function(cb) {
var slug = req.param('slug');
Room
.findOneBySlug(slug)
.populate('users', { where: { is_active: true, is_online: true } })
.populate('messages', { limit: 30, sort: 'createdAt DESC' })
.exec(cb)
},
pictures: ['room', function(cb, results) {
if (!results.room) return res.badRequest('User not found.');
Picture
.find({user: _.pluck(results.room.users, 'id')})
.where({'is_primary': true})
.exec(cb);
}],
map: ['pictures', function(cb, results) {
var room = results.room.toJSON();
room.users = room.users.map(function(user) {
user.pictures = results.pictures;
return user;
});
return cb(null, room);
}]
},
function finish(error, results) {
if (error) return res.serverError(error);
console.log(results.map)
}
);
}

Mongoose - remove array element in update

I have a JSON in this format:
{
_id:5522ff94a1863450179abd33,
userName:'bill',
__v:3,
friends:[
{
_id:55156119ec0b97ec217d8197,
firstName:'John',
lastName:'Doe',
username:'johnDoe'
},
{
_id:5515ce05207842d412c07e03,
lastName:'Adam',
firstName:'Foo',
username:'adamFoo'
}
]
}
And I would like to remove whole corresponding subarray. For example I want to remove user John Doe with ID 55156119ec0b97ec217d8197 so the result will be:
{
_id:5522ff94a1863450179abd33,
userName:'bill',
__v:3,
friends:[
{
_id:5515ce05207842d412c07e03,
lastName:'Adam',
firstName:'Foo',
username:'adamFoo'
}
]
}
So far I have this:
exports.delete = function (req, res) {
var friends = req.friends[0];
friends.update(
{'_id': req.body.friendsId},
{$pull: {'friends.friends': {_id: req.body.friendId}}}, function (err) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
res.json(friends);
}
});
};
But without result and also I'm not getting any error, it will stay just same as before. req.body.friendsId is ID of main array and req.body.friendId is ID of specific user which I want to pull.
Change your update query to this:
exports.delete = function (req, res) {
var friends = req.friends[0]; // assuming the friends object is your mongodb collection
friends.update(
{ '_id': req.body.friendsId },
{ $pull: {'friends': { _id: req.body.friendId } } }, function (err) {
if (err) {
return res.status(400).send({
message: getErrorMessage(err)
});
} else {
res.json(friends);
}
});
};
This will search for documents which have the friends array element _id value = req.body.friendsId and removes the specific array element from that array using the $pull operator.

Categories

Resources