How to find all users except current user with Mongoose - mongodb

I am trying to display a list of users but the logged-in user shouldn't see himself in the list. I can't make the request to get all users but current user to work.
router.get("/", auth, async (req, res) => {
try {
const users = await User.find({ user: { $ne: req.user.id } }).select([
"email",
"username",
"bio"
]);
res.json(users);
} catch (err) {
console.error(err.message);
res.status(500).send("Servor Error");
}
});
module.exports = router;
This request below gets the current user and it works.
router.get("/", auth, async (req, res) => {
try {
const user = await User.findOne({
user: req.user.id
});
if (!user) {
return res.status(400).json({ msg: "There is no profile for this user" });
}
res.json(user);
} catch (err) {
console.error(err.message);
res.status(500).send("Servor error");
}
});
module.exports = router;

You need to use _id field inside the query filter instead of user:
const users = await User.find({ _id: { $ne: req.user.id } }).select([
"email",
"username",
"bio"
]);

Related

How change name of parameter on express response

I'm using mongoose and I would like that when I get all users send me uid instead of _id.
const allUssers = (req, res, next) => {
try {
User.find({})
.select("username")
.select("email")
.select("image")
.exec((err, users) => {
if (err) {
return res.status(400).json({
ok: false,
msg: "Error listing users",
});
}
return res.status(200).json({
ok: true,
users: users,
});
});
} catch (err) {
return res.status(500).json({
ok: false,
msg: "Please contact with administrator",
});
}
};
You can update your schema to use an alias:
let User = new Schema({
_id: { type: String, alias: "uid" }
});
Or you can map your users to something different:
return res.status(200).json({
ok: true,
users: users.map(({ _id, ...user }) => ({ uid: _id, ...user }),
});

Update email only if it doesn't already exist in mongoDB database

I'm using this route to allow a user to change their email address. However, it currently lets them add an email address that is already used by another user. How can I prevent this (and send an alert in this situation). Also, I'm wondering if .findOneAndUpdate() is appropriate here as it may stop after finding the first one.
Thanks
app.post('/changeUserEmail', function (req, res) {
db.collection("userDB").findOneAndUpdate(
{username: req.user.username},
{ $set: {email: req.body.newEmail}},
{new: true},
(err, data) => {
if (err) {
console.log(err);
}
console.log(null, data);
}
)
res.render(process.cwd() + "/views/options", {
username: req.user.username,
email: req.body.newEmail,
alert: "Email changed"
});
});
You could first check if the email exists before you update something
app.post("/changeUserEmail", async function(req, res) {
let { username } = req.user;
let { newEmail } = req.body;
let emailExist = await db.collection("userDB").findOne({ email: newEmail });
if (emailExist)
return res.render(process.cwd() + "/views/options", {
alert: "Email already exists"
});
await db
.collection("userDB")
.findOneAndUpdate(
{ username },
{ $set: { email: newEmail } },
{ new: true }
);
res.render(process.cwd() + "/views/options", {
username,
email,
alert: "Email changed"
});
});

MongoDB + Express How to Optimize the code?

Hello everybody i have this bad code for me how i can optimize it ?
If i used SQL i can do used inner Queries in one query...
"User" it's only object from mongoose
getProfile: async (req, res) => {
const { id } = req.params;
try {
const {
image,
name,
gender,
about,
email,
phone,
address
} = await User.findById({ _id: id }).select('image name gender about email phone address');
const subscriptions = await Subscriber.countDocuments({ userId: id });
const subscribers = await Subscriber.countDocuments({ subscriberId: id });
const user = {
image,
name,
gender,
subscriptions,
subscribers,
about,
email,
phone,
address
};
res.json(user);
} catch (err) {
console.log(err);
}
}
PS.
I only study with this technologies
If i used spread operator of result of my query from User i have like this:
And that what i have in result
module.exports = {
getProfile: async (req, res) => {
const { id } = req.params;
try {
const [data, subscriptions, subscribers] = await Promise.all([
User.findById( { _id: id },
{
__v: false,
password: false,
date: false,
_id: false
},
),
Subscriber.countDocuments({ userId: id }),
Subscriber.countDocuments({ subscriberId: id })
])
const user = {
...data._doc,
subscriptions,
subscribers
}
res.json(user);
} catch (err) {
console.log(err);
}
}
Since all of your queries are independent, the best we can do is execute all of them parallelly with Promise.all(). Try something like this:
getProfile: async (req, res) => {
const { id = _id } = req.params;
try {
const getUser = User.findById({ _id }).select('image name gender about email phone address');
const getSubscriptions = Subscriber.countDocuments({ userId: id });
const getSubscriber = Subscriber.countDocuments({ subscriberId: id });
const [userData, subscriptions, subscribers] = await Promise.all([getUser, getSubscriptions, getSubscriber]);
const user = {
...userData,
subscriptions,
subscribers,
};
res.json(user);
} catch (err) {
console.log(err);
}
}
Hope this helps :)
You can embed subscriptions [array of documents] in the User model. But bear in mind that could put limitations on your api, if subscriptions might be accessed regardless of its user.

How to aggregate two collections from MongoDB using Express?

So I currently have two collections. One that is 'posts' and the other one that is 'users'
This is post:
_id
title
text
user
date
and this is users:
_id
username
email
password
I'm trying to use aggregate in the following way:
router.get('/:user_id', async (req, res) => {
try {
// const profile = await User.findById(req.params.user_id);
const profile = await User.agregate([
{
'$lookup': {
'from': 'posts',
'localField': '_id',
'foreignField': 'user',
'as': 'posts'
}
}
]);
// Verify profile exists
if (!profile) return res.status(400).json({ msg: 'Profile not found' });
res.json(profile);
} catch (err) {
console.error(err.message);
if (err.kind == 'ObjectId') {
return res.status(400).json({ msg: 'Profile not found' });
}
res.status(500).send('Server error');
}
});
Notice that the first profile constant is commented but that's the one I use to fetch the users data according to the _id(req.params.user_id) of X user.
Now what I would like to create is to display all of the posts created by X user by accessing to their profile, so I need to match the corresponding user, I need to pass the req.params.user_id.
This is the new code that I have which is not working:
router.get('/:user_id', async (req, res) => {
try {
// const profile = await User.findById(req.params.user_id);
const profile = await User.agregate([
{
'$lookup': {
'from': 'posts',
'localField': '_id',
'foreignField': 'user',
'as': 'posts'
}
}, {
$unwind: "$posts"
}, {
$match: {
"posts.user": req.params.user_id
}
}
]);
// Verify profile exists
if (!profile) return res.status(400).json({ msg: 'Profile not found' });
res.json(profile);
} catch (err) {
console.error(err.message);
if (err.kind == 'ObjectId') {
return res.status(400).json({ msg: 'Profile not found' });
}
res.status(500).send('Server error');
}
});
The error that is displayed in my console.log is 'user.aggregate is not a function'. Hopefully I could explain myself, thanks!.
I just want to add a new field(posts array) into the the users collection.
If anyone has come to the same requirement just as I did, here it is the solution after two days of researching and asking lol.
router.get('/:user_id', async (req, res) => {
try {
const userId = req.params.user_id;
const [profile, postsByUser] = await Promise.all([User.findById(userId, '-password'), Post.find({ user: userId }).populate('user', ['_id', 'username', 'avatar']).sort({ date: -1 })]);
// Verify profile exists
if (!profile) return res.status(400).json({ msg: 'Profile not found' });
// res.json(profile);
res.json({ ...profile.toJSON(), postsByUser });
} catch (err) {
console.error(err.message);
if (err.kind == 'ObjectId') {
return res.status(400).json({ msg: 'Profile not found' });
}
res.status(500).send('Server error');
}
});
Even nowadays that's a useful example. Except the typo:
const profile = await User.agregate([
should be
const profile = await User.aggregate([

Facebook Graph returns a different value than is saved using passport-facebook

I have an application where the user logs in using facebook account, saving the id, name and email. I'm using https://github.com/jaredhanson/passport-facebook
UserSchema.statics.findOrCreateFaceBookUser = function(profile, done) {
var User = this;
User.findOne({
'email': profile.emails[0].value
}, function(err, user) {
if (err) {
throw err;
}
if (user) {
user.facebook = {
id: profile.id,
email: profile.emails[0].value,
name: profile.displayName
};
user.save(function(err) {
if (err) {
return next(err);
} else {
// done(null, user);
}
});
done(null, user);
} else {
User.findOne({
'facebook.id': profile.id
}, function(err, user) {
if (err) {
throw err;
}
//if (err) return done(err);
if (user) {
done(null, user);
} else {
User.create({
firstName:profile.name.givenName,
lastName:profile.name.familyName,
email: profile.emails[0].value,
gender:profile.gender,
image:"http://graph.facebook.com/"+profile.id+"/picture?type=normal",
facebook: {
id: profile.id,
email: profile.emails[0].value,
name: profile.displayName
}
}, function(err, user) {
if (err) {
throw err;
}
done(null, user);
});
}
});
}
});
The problem is that I need to fetch facebook friends who are also using the application, but the "id" returned by facebook graph does not match what I'm persisting in the application.
https://graph.facebook.com/me/friends?fields=id,name&access_token=xpto
The "profile.id" received the passport-facebook is different from the facebook graph field "id"