Reputation: 73
I'm working with mongoose and want to reach all the subdocuments within a subdocument. In short, I want to return all booking subdocuments that are stored in the dentist subdocuments that are stored in the clinic documents.
Right now my solution contain a lot of loops, but there have to be a better way. The code below works and describes what my ambition is. I'm willing to re-arrange the schema structure if needed. Please help me to improve on it.
router.post('/available-times', function (req, res) {
let available_times = [];
Clinic.find()
.then((clinics)=> {
clinics.forEach((clinic) => {
clinic.dentists.forEach((dentist) => {
dentist.schedule.forEach((booking) => {
if(!booking.reserved){
available_times.push(booking)
}
})
})
});
const response = {
success: true,
result: available_times,
}
res.json(response)
})
.catch(err => res.status(400).json("Error: " + err));
})
The Clinic Schema:
const clinicSchema = new Schema({
address: { type: String},
clinic_name: { type: String},
contact_person: { type: String},
dentists: [Dentist.schema],
description: { type: String},
email: { type: String},
isVerified: { type: Boolean, default: false },
location: { type: String},
logo_url: { type: String},
});
The Dentist Schema:
const dentistSchema = new Schema({
biography: { type: String},
languages_spoken: [String],
name: { type: String},
offered_services: [String],
picture_url: { type: String},
reviews: { type: Array},
schedule: [Booking.schema],
});
The Booking Schema:
const bookingSchema = new Schema({
title: { type: String},
start: { type: Date},
end: { type: Date},
customer_email: { type: String},
customer_name: { type: String},
customer_phone: { type: String},
dentist_id: { type: String},
dentist_name: { type: String},
clinic_id: { type: String},
price: { type: Number},
reserved: { type: Boolean, default: false },
});
Upvotes: 1
Views: 118
Reputation: 318
I guess the structure of the collection Clinic
looks like this
[
{
_id: ObjectId('5fa36e4d0e5796a0221bad0d'),
dentists: [
{schedule: [{booking: {reserved: true, foo: 'bar1'}}]},
{
schedule: [
{booking: {reserved: false, foo: 'bar2'}},
{booking: {reserved: true, foo: 'bar3'}}
]
}
]
},
{
_id: ObjectId('5fa373340e5796a0221bad0e'),
dentists: [
{schedule: [{booking: {reserved: true, foo: 'bar4'}}]},
{schedule: [{booking: {reserved: false, foo: 'bar5'}}]}
]
}
]
if the structure is correct, then you can run the aggregation
Clinic.aggregate(
[
{
$project: {
_id: 0,
temp: '$dentists.schedule.booking'
}
},
{
$unwind: {
path: '$temp'
}
},
{
$unwind: {
path: '$temp'
}
},
{
$match: {
'temp.reserved': true
}
},
{
$group: {
_id: null,
available_times: {
$addToSet: '$temp'
}
}
}
]
)
and you can get the result like
{
_id: null,
available_times: [
{reserved: true, foo: "bar4"},
{reserved: true, foo: "bar3"},
{reserved: true, foo: "bar1"}
]
}
Upvotes: 1