So I'm having the issue where I need to filter my documents based on the result of a .populate. I can't simply do it in a match
parameter in the populate()
options because I want to check the size of the resulting array from populate.
Example:
Hotel model:
var HotelSchema = new Schema({
name: {
type: String,
required: true,
}
});
HotelSchema.virtual('bookings', {
ref: 'Booking',
localField: '_id',
foreignField: 'hotelId',
justOne: false,
});
Booking model:
var BookingSchema = new Schema({
startDate: {
type: Date,
required: true,
}
endDate: {
type: Date,
required: true,
}
hotelId: {
type: ObjectId,
required: true,
}
});
So in this scenario I would want to do a query on hotels that have no bookings (actually want to do with availability, but simplified it for the example). I can do this by joining to bookings (filtered based on dates), and check if any bookings exist.
I managed to do this with a $lookup
like so:
Hotel.aggregate([
{ $lookup: { from: 'bookings', localField: '_id', foreignField: 'hotelId', as: 'bookings' } },
{ $match: { bookings: { $size: 0 }}}
]);
(as a side note, is there a way to only lookup the size of bookings, rather then returning each object? I couldn't seem to figure that out)
But when I do a .populate
I can't seem to find any where to add this condition. Something like this is no good:
Hotel.find({})
.populate({ path: 'bookings', match: { bookings: { $size: 0 } } })
The reason I want to use populate, is because of performance issues as explained here: https://github.com/Automattic/mongoose/issues/3683, and in the case where multiple databases are used, as $lookup would not work in that situation
It appears due to the layout of this relationship, a $lookup would take far longer than a populate, because a full scan of bookings
would be done for every Hotel
.