I need to filter the fields of the result obtained as populate with the mongoose select()
function. I need only the title
, content
, image
fields of the Post
object and the name
and avatar
of the User
object.
In the User schema I have created a virtual
that references the userId
field of the Post schema.
// ========= MODELS =============
const mongoose = require('mongoose');
const { Schema } = mongoose;
const userSchema = new Schema({
name: { type: String, trim: true, required: true },
email: { type: String, trim: true, required: true },
password: { type: String, trim: true, required: true },
description: { type: String, trim: true, required: true },
avatar: { type: String, trim: true, required: true },
});
userSchema.virtual('ownerPost', {
ref: 'Post',
localField: '_id',
foreignField: 'userId',
});
const postSchema = new Schema(
{
title: { type: String, trim: true, lowercase: true, required: true },
content: { type: String, required: true },
summary: {type: String, required: true },
image: { type: String, trim: true, required: true },
userId: { type: Schema.Types.ObjectId, ref: 'User', required: true }
});
const Post = mongoose.model('Post', postSchema);
const User = mongoose.model('User', userSchema);
// ========= CONTROLLERS =============
const getPostById = async (req, res, next) => {
try {
const { id } = req.params;
const post = await Post.findById(id)
.populate('userId')
// it doesn't work
// .select(['title', 'content', 'image', 'userId.name', 'userId.avatar']);
// it doesn't work
// .select(['title', 'content', 'image', 'name', 'avatar']);
return res.status(200).json(post);
} catch (error) {
return next(error);
}
};
// ========= RESPONSE WITHOUT SELECT IN GET POST BY ID =============
{
"title": "Example Title",
"content": "<h1>This is content</h1>",
"summary": "<h4>This is summary</h4>",
"image": "https://upload.wikimedia.org/wikipedia/commons/0/02/Great_Wave_off_Kanagawa_-_reversed.png",
"userId": {
"name": "peter",
"email": "peter80@gmail.com",
"password": "$2b$12$LaJWX1/A3ATq4c/tgNIs.uwhnpZGwsqBePFLxIFCDa9gwjitcalda",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.",
"avatar": "https://pngimage.net/wp-content/uploads/2018/05/avatar-profile-png-2.png",
"id": "5e9066e5bc3e6a415134396e"
},
"id": "5e90677cbc3e6a4151343970"
}
// ========= RESPONSE WITH SELECT IN GET POST BY ID =============
{
"title": "titulo de ejemplo",
"content": "<h1>Esto es un contenido de ejemplo</h1>",
"image": "https://upload.wikimedia.org/wikipedia/commons/0/02/Great_Wave_off_Kanagawa_-_reversed.png",
"userId": {
"name": "peter",
"email": "peter80@gmail.com",
"password": "$2b$12$LaJWX1/A3ATq4c/tgNIs.uwhnpZGwsqBePFLxIFCDa9gwjitcalda",
"description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor.",
"avatar": "https://pngimage.net/wp-content/uploads/2018/05/avatar-profile-png-2.png",
"id": "5e9066e5bc3e6a415134396e"
},
"id": "5e90677cbc3e6a4151343970"
}
you can use the select method to select what you need from the current collection
regarding the populated field, you can pass an object to the populate method to indicate the path you will populate, and selecting which items from that collection
your query should be something like that
Post.findById(id).select('title content image userId').populate({ path: 'userId', select: 'name avatar' })