mongodb - exclude a specific field from results array - mongodb

Below is partnership collection which has users 1 and 2 who participated. One of the users is the current logged in user available as req.user._id and I am listing the user's partners.
{
"_id": {
"$oid": "6381697ddddbdb42b4682fb7"
},
"users": [{
"$oid": "user_one_id"
}, {
"$oid": "user_two_id"
}],
}
I am getting the fields of the user who is partner from PartnerModel (excluding the req.user._id). Assuming in this case, req.user._id is user_one_id
let partners =
await userPartnerModel.find({
users: { $in: [req.user._id] }
}).sort({ createdAt: -1 })
.populate({
path: 'users',
select: 'profilePic firstName',
model: userModel
})
res.status(200).json(partners)
The issue is that partners result also includes the req.user.
The result I am getting now is:
{
"users":[
{
"firstName":"User One",
"profilePic":"https://image.jpg",
"_id":"63729a9a73f736476cbdd0cc"
},
{
"firstName":"User Two",
"profilePic":"https://image2.jpg",
"_id":"63728ae473f736476cbdd0be"
}
But the results should not include req.user._id which is "User One"

Hey you can use the select function to allow only the field you want. By default the _id field is allowed you can disallow it by adding -id. For your case you can use this query:
let partners =
await userPartnerModel.find({
users: { $in: [req.user._id] }
}).sort({ createdAt: -1 })
.populate({
path: 'users',
select: 'profilePic firstName -_id',
model: userModel
})

Related

How do I query to fetch number of Posts made by a User using mongoose?

So I'm trying to fetch the total number of posts done by a specific user.
Models
Post.ts (In post model I have user ref)
user: {
type: Schema.Types.ObjectId,
ref: "User",
required: [true, "Please provide user ID."],
},
I tried
const posts = await Post.find({ user: req.user._id});
const postCount = posts.length;
But I want to aggregate the User so I can get the user data along with the post counts.
what I tried is below but I'm getting 0 number of posts.
const user = await User.aggregate([
{
$lookup: {
from: "post",
let: { userId: "$_id" },
pipeline: [{ $match: { $expr: { $eq: ["$$userId", "$userId"] } } }],
as: "posts_count",
},
},
{ $addFields: { posts_count: { $size: "$posts_count" } } },
]);
I searched but couldn't find any related answer.
You can slightly alter the query as follows. From the post model, I see that the field referenced for user collection is user. In the aggregate, you have used $userId.
const user = await User.aggregate([
{
$lookup: {
from: "post",
let: { userId: "$_id" },
pipeline: [{ $match: { $expr: { $eq: ["$$userId", "$user"] } } }],
as: "posts_count",
},
},
{ $addFields: { posts_count: { $size: "$posts_count" } } },
]);
Let me know if this helps. Thanks

Get all the data of a field but populate only 10 of them in mongodb

I have User model with this friends schema:
friends: [{
type : Schema.Types.ObjectId,
ref: 'User'
}],
I tried this:
const user = await User.findById({ _id: userID })
.populate({ path: 'friends', options: { limit: 10 } })
this works.... but it actually loads and populate only 10 of the friends. I need to load all of them to display the count of the friends and populate 10 to display user avatar and such things...
How can I do this?
Also I have simimar problem with this schema:
comments: [{
user: {
type : Schema.Types.ObjectId,
ref: 'User'
},
comment: {
type: String
},
date: {
type: Date,
default: Date.now
}
}]
I tried this:
It populate all of the comments.user but how should I do this here because this:
const user = await User.findById({ _id: userID })
.populate({ path: 'comments.user', options: { limit: 10 } })
doesn't limit them....
You might be able to fix that by using aggregation + populate kind of like this (untested):
var result = User.aggregate([{
$match: { // filter by user id
_id: userID
}
}, {
$addFields: { // add count of friends
numberOfFriends: { $size: "$friends" }
}
}]);
and then
User.populate(result, { path: "friends", options: { limit: 10 } }, /* your callback */);

Mongoose pull ObjectId from array

i'm trying to do a pretty simple operation, pull an item from an array with Mongoose on a Mongo database like so:
User.update({ _id: fromUserId }, { $pull: { linkedUsers: [idToDelete] } });
fromUserId & idToDelete are both Objects Ids.
The schema for Users goes like this:
var UserSchema = new Schema({
groups: [],
linkedUsers: [],
name: { type: String, required: true, index: { unique: true } }
});
linkedUsers is an array that only receives Ids of other users.
I've tried this as well:
User.findOne({ _id: fromUserId }, function(err, user) {
user.linkedUsers.pull(idToDelete);
user.save();
});
But with no luck.
The second option seem to almost work when i console the lenghts of the array at different positions but after calling save and checking, the length is still at 36:
User.findOne({ _id: fromUserId }, function(err, user) {
console.log(user.linkedUsers.length); // returns 36
user.linkedUsers.pull(idToDelete);
console.log(user.linkedUsers.length); // returns 35
user.save();
});
So it looks like i'm close but still, no luck. Both Ids are sent via the frontend side of the app.
I'm running those versions:
"mongodb": "^2.2.29",
"mongoose": "^5.0.7",
Thanks in advance.
You need to explicitly define the types in your schema definition i.e.
groups: [{ type: Schema.Types.ObjectId, ref: 'Group' }],
linkedUsers: [{ type: Schema.Types.ObjectId, ref: 'User' }]
and then use either
User.findOneAndUpdate(
{ _id: fromUserId },
{ $pullAll: { linkedUsers: [idToDelete] } },
{ new: true },
function(err, data) {}
);
or
User.findByIdAndUpdate(fromUserId,
{ $pullAll: { linkedUsers: [idToDelete] } },
{ new: true },
function(err, data) {}
);
I had a similar issue. I wanted to delete an object from an array, using the default _id from mongo, but my query was wrong:
const update = { $pull: { cities: cityId }};
It should be:
const update = { $pull: { cities: {_id: cityId} }};

getting count within a findOne of a mongoose schema array field

I want to use Mongoose to return information about a user to populate their profile. I've been using findOne to populate a list of their comments along with basic profile information through embedded documents and with .populate. I want to get a count of the friends that they have by counting how many objects are in the friends array.
It looks like aggregate is one of doing that, but how can I use both? or is there a simple way of doing a count in the findOne query?
var UserSchema = new Schema({
username: String,
comments : [{ type: Schema.Types.ObjectId, ref: 'Comment' }],
friends: [
{
id: { type: Schema.Types.ObjectId, ref: 'User' },
permission: Number
}
]
})
var User = mongoose.model('User', UserSchema);
var Comment = mongoose.model('Comment', CommentSchema);
app.get('/profile/:username', function(req, res) {
User
.findOne({ username: req.params.username }, 'username friends -_id')
.populate({
path: 'current',
model: 'Comment',
select: 'comment author -_id date',
populate: {
path: 'author',
model: 'User',
select: 'username firstName lastName -_id'
}
})
.exec(function(err, user) {
//
})
)}
If user returns with friends array, why don't you return just user.friends.length ?
If you want just count, use this
User.aggregate([
{
$match: { username: req.params.username }
},
{
$unwind: "$comments"
},
{
$lookup: {
from: "Comment",
localField: "comments",
foreignField: "_id",
as: "comments"
}
},
{
"$group": {
"_id": "$_id",
"friends": { "$first": "$friends"},
"comments": { "$push": "$comments" }
}
},
{
$project: {
_id: 0,
count: {$size: '$friends'},
comments: 1,
username: 1
}
}
]).exec() ...

Meteor Mongo add subdocument

I have a collection documents MasterPropinsis like this :
{
"_id": "4HSb7bbjFBzRSftXu",
"nama": "Yogyakarta",
"kabupaten": [
{
"id": "KulonProgo",
"nama": "Kulon Progo",
"kecamatan": [{ "nama": "Kalibawang" },{ "nama": "Nanggulan" }]
},
{
"id": "Sleman",
"nama": "Sleman",
"kecamatan": [{ "nama": "Depok" },{ "nama": "Berbah" }]
},
{
"id": "Bantul",
"nama": "Bantul",
"kecamatan": []
}
]
}
At kabupaten:Bantul, I want to Add subdocument kecamantan:XXX, with this code :
Masterpropinsis.update(
{
_id: Session.get('idKabupaten').toString(),
'kabupaten.id': Session.get('idKecamatan').replace(" ", "")
},
{
$addToSet: {
'kabupaten.kecamatan': {
nama: nama,
createdAt: new Date(),
createBy: CreateBy,
createByID: CreateByid
}
}
},
{
validate: true
});
But I get this error:
Uncaught Error: Not permitted. Untrusted code may only update documents by ID. [403]
Here is an example try this
var docId = Session.get('idKabupaten'); // usally toString is not nesserry unless you do something unusual
Masterpropinsis.update({_id: docId }, {
$push: {
'kabupaten.kecamatan': {
nama: nama,
createdAt: new Date(),
createBy: CreateBy,
createByID: CreateByid
}
}
}); // validate true also is the default unless again you do something unusual
you can see we only supply {_id: docId} in the selector the error says in client you can only update by the ID in the server you can do any selector. Also hopefully you can have Allow/Deny rules to allow updates from the client? http://docs.meteor.com/#/full/allow