Mongoose/MongoDB:如何查询关联Owner的所有Reservation
获取指定Owner关联所有Reservation的最优方案
方案1:给ReservationSchema直接加owner字段
这是性能最优的方案,属于合理的数据冗余,虽然多存了一份owner的ID,但能把查询效率拉满。
- 具体操作:在ReservationSchema里新增owner字段,和traveler字段类型一致
const ReservationSchema = new Schema({ traveler: { type: Schema.Types.ObjectId, ref: DOC_TYPE.USER, required: true, }, property: { type: Schema.Types.ObjectId, ref: DOC_TYPE.PROPERTY, required: true, }, owner: { // 新增关联owner的字段 type: Schema.Types.ObjectId, ref: DOC_TYPE.USER, required: true, } // 其他业务字段 }) - 好处:查指定owner的预订记录时,直接一条
find({owner: 目标ID})就能搞定,一次查询出结果,速度最快 - 注意事项:要保证数据一致性——创建Reservation时得同步把对应Property的owner ID存进来;如果Property换了owner,得批量更新关联的所有Reservation(可以用Mongoose的中间件或者MongoDB触发器实现)
方案2:用聚合查询关联Property和Owner
不用改现有Schema,直接通过MongoDB的$lookup关联集合查询
- 具体操作:用聚合管道先关联Property表,再过滤owner
const targetOwnerId = '目标Owner的ObjectId' const reservations = await Reservation.aggregate([ { $lookup: { from: 'properties', // 这里填Property对应的集合名,不是模型名 localField: 'property', foreignField: '_id', as: 'propertyDetail' } }, { $unwind: '$propertyDetail' }, // 把关联出来的数组展开(每个Reservation只对应一个Property) { $match: { 'propertyDetail.owner': targetOwnerId } }, // 可选:如果不需要返回Property的详情,用$project过滤掉 { $project: { propertyDetail: 0 } } ]) - 性能说明:
- 没加索引的话,
$lookup会全表扫Property集合,性能拉胯 - 必须给两个字段加索引:
PropertySchema的owner字段,以及ReservationSchema的property字段(外键字段本来就该加索引)PropertySchema.index({ owner: 1 }) ReservationSchema.index({ property: 1 }) - 加索引后性能会提升,但还是不如方案1直接查询快,毕竟涉及跨集合关联操作
- 没加索引的话,
方案3:分步查询(先查Property再查Reservation)
逻辑最直观的方案,适合新手上手,不用写复杂的聚合
- 具体操作:
const targetOwnerId = '目标Owner的ObjectId' // 第一步:先拿到这个Owner名下的所有Property ID const propertyList = await Property.find({ owner: targetOwnerId }, '_id') const propertyIds = propertyList.map(item => item._id) // 第二步:查关联这些Property的所有Reservation const reservations = await Reservation.find({ property: { $in: propertyIds } }) - 性能说明:
- 同样要给
PropertySchema的owner字段加索引,不然第一步查询会很慢 - 如果Owner名下的Property数量不多(几十上百个),
$in查询性能没问题;要是数量上千,$in的效率会明显下降,这时候不如选方案1或者加了索引的方案2
- 同样要给
- 好处:逻辑简单,不用改Schema,也不用搞复杂的聚合管道
选哪个?
- 如果查询Owner的预订记录是高频操作,优先选方案1,用一点数据冗余换极致性能,只要做好数据一致性维护就行
- 如果只是低频查询,或者不想改现有Schema,选方案3(逻辑简单)或者方案2(一步聚合查询),但一定要记得加索引
内容的提问来源于stack exchange,提问作者Michael Koska
相关产品推荐
相关产品推荐

