I am trying to sort populated array based on the nested and populated field using mongoose but it is not working.
Here are my modals.
const campaignSchema = new Schema(
{
name: { type: String, required: true },
prospects: [{ type: mongoose.Types.ObjectId, ref: "Prospect" }],
}
);
const prospectSchema = new Schema(
{
strategy: { type: String, trim: true },
contact: { type: mongoose.Types.ObjectId, ref: "Contact", required: true },
primaryCaller: { type: mongoose.Types.ObjectId, ref: "Contact" },
}
);
const contactSchema = new Schema(
{
firstName: { type: String, required: true },
lastName: { type: String, required: true },
}
);
Now I am trying to populate prospects and contact in each prospect in and sort them by contact.firstName using the following code.
const campaign = await Campaign.findOne({ _id: id }).populate({
path: "prospects",
populate: [
{ path: "contact", select: "firstName lastName" },
{ path: "primaryCaller", select: "firstName lastName" },
],
options: {
sort: "contact.firstName",
},
}).lean();
I tested it with sort: "strategy", and it is working fine with it.
I also tried Aggregations but it also didn't help.
Related
I have two collections in MongoDB database, Post and User. Each post contains the creator's ObjectId. When fetching all posts from the database, I want to add the name information, which is a field of User/creator. I tried to access the name field by post.creator.name, but it is not working.
const postSchema = new Schema(
{
title: {
type: String,
required: true,
},
category: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
imageUrl: {
type: String,
required: true,
},
creator: {
type: Schema.Types.ObjectId,
ref: "User",
required: true,
},
},
{ timestamps: true }
);
const userSchema = new Schema({
email: {
type: String,
required: true,
},
password: {
type: String,
required: true,
},
name: {
type: String,
required: true,
},
status: {
type: String,
required: true,
},
isExpert: {
type: Boolean,
required: true,
},
posts: [
{
type: Schema.Types.ObjectId,
ref: "Post",
},
],
});
exports.getPosts = (req, res, next) => {
Post.find({}).then((posts) => {
const postsWithAuthorName = posts.map(post => {
return {
...post,
name: post.creator.name
}
})
res.status(200).json({
posts: postsWithAuthorName,
});
});
};
Try this
Post.find({}).populate('creator', 'name')
See populate doc for reference.
When you query posts, creator is just an ObjectId, so you can't just call .name on it. To make it work you need to lookup this data by using e.g. populate.
I'm new to NoSQL, in this case is MongoDB. I'm trying to make an API using ExpressJS and Mongoose. that have some data models
User.js
const UserSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
min: 3,
max: 50,
unique: true,
},
email: {
type: String,
required: true,
max: 50,
unique: true,
},
password: {
type: String,
required: true,
min: 6,
},
profilePicture: {
type: Schema.Types.ObjectId,
ref: "Image",
},
}
Image.js
const ImageSchema = new mongoose.Schema(
{
desc: {
type: String,
},
url: {
type: String,
},
},
{ timestamps: true }
)
Post.js
const PostSchema = new mongoose.Schema(
{
username: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
desc: {
type: String,
max: 300,
required: true,
},
images: [
{
type: Schema.Types.ObjectId,
ref: "Image",
},
],
comments: [
{
type: Schema.Types.ObjectId,
ref: "Comment",
},
],
}
)
Comment.js
const CommentSchema = new mongoose.Schema(
{
user: {
type: Schema.Types.ObjectId,
ref: "User",
},
text: {
type: String,
required: true,
trim: true,
},
}
Now I want to perform a query that gets all comments based on specific postId. And the response data must include User data and image url that related to User. I tried this to get comment data
const comments = await Comment.find({post: req.params.postId}).populate("user")
It returned Comment with User data, but not include Image. How do I perform that query?
Try this (using the pupulate method with object configuration):
const comments = await Comment.find({post: req.params.postId}).populate({
path: 'user',
populate: {
path: 'profilePicture'
}
})
Here you can also select particular fields of each schema for example.
Let me know if it works for you.
Reference
Here is my schema, I want to join the address in ScheduleSchema to addressDetails in CustomerSchema to list the all address details in a table, how to achieve this?
const CustomerSchema = new Schema(
{
addressDetails: [
{
block: {
type: String,
},
building_number: {
type: String,
},
is_default: {
type: Boolean,
default: false,
},
},
],
},
const SheduleSchema = new Schema(
{
customer: {
type: ObjectId,
required: true,
ref: "Customer",
},
address: {
type: ObjectId
},
week: {
type: String
}
},
schemaOptions
);
you must to use ref and populate for address key check the documnetation, and add this property to the Schemas like this :
const SheduleSchema = new Schema(
{
customer: {
type: ObjectId,
required: true,
ref: "Customer",
},
address: {
type: mongoose.Types.ObjectId,
ref: "Customer",
},
week: {
type: String
}
},
schemaOptions
);
use populate for get all addresses wit details
await SheduleSchema.find().populate({
path : "address"
})
I have been building a chat application,and I am storing user with a schema
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: {
type: ContactSchema,
},
});
and ContactSchema as
const ContactSchema = new Schema({
contactUserId: {
type: String,
required: true,
},
});
the problem is that, when I try to find the user in mongo shell with findOne, It retrieves the user with contacts array:
{
"_id" : "49Ff7aRn4baPuTVFefQLulbMIeE2",
"username" : "john",
"email" : "doe#gmail.com",
"__v" : 0,
"contacts" : [
{
"_id" : ObjectId("5eb07958b0315c6303505f74"),
"contactUserId" : "RHOCbyCtvjQfFzFukxiwS9wV1ly1"
},
{
"_id" : ObjectId("5eb07e4eff338702ba455c8a"),
"contactUserId" : "tGCkdHh55UgkG8AW0Ab6S9guwcF3"
}
]
}
but when I try to use mongoose findOne, It retrieves the user with contacts field as an object:
{ _id: '49Ff7aRn4baPuTVFefQLulbMIeE2',
username: 'john',
email: 'doe#gmail.com',
__v: 0,
contacts:
{ '0':
{ _id: 5eb07958b0315c6303505f74,
contactUserId: 'RHOCbyCtvjQfFzFukxiwS9wV1ly1' },
'1':
{ _id: 5eb07e4eff338702ba455c8a,
contactUserId: 'tGCkdHh55UgkG8AW0Ab6S9guwcF3' },
_id: 5eb086555cbcb03801350d76 } }
Is there any workaround for this ?
That's because of your mongoose UserSchema :
Change contacts: { type: ContactSchema } of type Object to contacts: [ContactSchema] of type array of Objects as like below :
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: [ContactSchema],
});
On mongo shell, As you don't have any conversion so it's pretty simple & returns the document from DB as is.
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: [ContactSchema]
});
contacts should be mentioned as above instead of
const UserSchema = new mongoose.Schema({
_id: {
type: String,
required: true,
},
email: {
type: String,
required: true,
},
username: {
type: String,
required: true,
},
contacts: {
type: ContactSchema,
},
});
How I can display details data of a profile when those data stored in more than one collections
tried this link
const profile = await userKushala
.find({_id: '5cd407c741f9e7373f10362c'})
.populate({
path: 'settingId',
populate : {
path : 'specialty',
populate : {
path: 'hospital_attached'
}
}
})
// First Collection(Basic Info.)
const userRegisterSchema = new Schema({
userType: {
type: String,
required: true
},
mobile: {
type: Number,
required: true,
unique: true
},
userId: {
type: String,
required: true
},
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
age: {
type: Number,
required: true
},
gender: {
type: String,
required: true
},
settingId: {
type: mongoose.Schema.Types.ObjectId,
ref: 'providerSetting'
}
})
// Second Collection(Detailed Info.)
const serviceProfileUpdate = new Schema({
specialty :[{
type: mongoose.Schema.Types.ObjectId,
ref: 'specialtyMasterCsv'
}],
category: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'categoryMasterCsv'
}],
subscriptionPlan: {
type: mongoose.Schema.Types.ObjectId,
ref: 'planMasterCsv'
},
medicine: {
type : mongoose.Schema.Types.ObjectId,
ref: 'kushalaUser'
}
})
//Data in Mongo
{
"_id":{
"$oid":"5cd93ea6bd96e43664f49bf3"
},
"specialty":[
{
"$oid":"5cda85f26ffe60259a75ba17"
},
{
"$oid":"5cda85f26ffe60259a75ba18"
}
],
"category":[
{
"$oid":"5cda85f26ffe60259a75ba17"
},
{
"$oid":"5cda85f26ffe60259a75ba18"
}
],
"subscriptionPlan":{
"$oid":"5cda85f26ffe60259a75ba17"
},
"medicine":{
"$oid":"5cd407c741f9e7373f10362c"
},
"__v":{
"$numberInt":"0"
}
}
Expected Result will be from all the collections data should fetch but with the code I have it's giving the result till specialty but after that it's printing only ObjectID
This is what I have done and it's working still if anyone has a better solution, most welcome. Hope it helps someone.
const profile = await userKushala
.find({_id: '5cd407c741f9e7373f10362c'})
.populate({
path: 'settingId',
populate : {
path : 'specialty category subscriptionPlan medicine'
}
})
Try to populate like this:
.populate([
{path:'category',model:'categoryMasterCsv'},
{path:'subscriptionPlan',model:'planMasterCsv'},
{path:'medicine',model:'kushalaUser'}])
This is the method I use daily.