如何在Mongoose中通过City的zipCode属性查询Restroom文档
问题:通过邮编查询关联的卫生间列表
已定义的Mongoose Schema
const AddressSchema = new Schema<IAddress>( { street: { type: String, required: true, }, }, { timestamps: true, versionKey: false, } );
const CitySchema = new Schema<ICity>( { name: { type: String, required: true, }, zipCode: { type: String, required: true, }, }, { timestamps: true, versionKey: false, } );
const RegionSchema = new Schema<IRegion>( { name: { type: String, required: true, }, code: { type: String, required: true, }, }, { timestamps: true, versionKey: false, } );
const RestroomSchema = new Schema<IRestroom>( { name: { type: String, required: true }, avgRating: { type: Number, required: true }, fullAddress: { address: { type: Schema.Types.ObjectId, ref: 'addresses', required: true }, city: { type: Schema.Types.ObjectId, ref: 'cities', required: true }, region: { type: Schema.Types.ObjectId, ref: 'regions', required: true } } }, { timestamps: true, versionKey: false } );
需求与问题
Restroom的fullAddress字段关联了Address、City、Region的ID,现在需要通过City的zipCode属性查询所有匹配该邮编的Restroom列表。你尝试了以下代码,但不确定是否正确:
RestroomModel.findOne({ _id: id }) .populate({ path: 'fullAddress.address', populate: 'street' }) .populate({ path: 'fullAddress.city', populate: 'zipCode' }) .populate({ path: 'fullAddress.region', populate: 'name'});
代码问题分析
你写的这段代码是根据ID查询单个Restroom文档并填充关联数据,并没有实现“按邮编查询Restroom列表”的核心需求。另外populate的写法也有误:不需要在populate里嵌套指定字段名,直接填充整个关联文档即可。
正确实现方式
方法一:分步查询(简单易懂)
先根据邮编找到对应的City,再通过City的ID查询关联的Restroom:
// 1. 根据目标邮编查找对应的城市 const targetCity = await CityModel.findOne({ zipCode: '你的目标邮编' }); if (!targetCity) { return []; // 无匹配邮编的城市,返回空列表 } // 2. 查询所有关联该城市的卫生间,并填充完整地址信息 const restrooms = await RestroomModel.find({ 'fullAddress.city': targetCity._id }) .populate('fullAddress.address') .populate('fullAddress.city') .populate('fullAddress.region');
方法二:聚合查询(单次数据库请求)
用MongoDB的聚合框架一次完成关联与查询:
const restrooms = await RestroomModel.aggregate([ // 关联City集合,匹配城市ID { $lookup: { from: 'cities', localField: 'fullAddress.city', foreignField: '_id', as: 'matchedCity' } }, // 过滤出邮编匹配的结果 { $match: { 'matchedCity.zipCode': '你的目标邮编' } }, // 关联Address集合 { $lookup: { from: 'addresses', localField: 'fullAddress.address', foreignField: '_id', as: 'fullAddress.address' } }, // 关联Region集合 { $lookup: { from: 'regions', localField: 'fullAddress.region', foreignField: '_id', as: 'fullAddress.region' } }, // 将lookup返回的数组转为单个对象 { $set: { 'fullAddress.address': { $first: '$fullAddress.address' }, 'fullAddress.city': { $first: '$matchedCity' }, 'fullAddress.region': { $first: '$fullAddress.region' } } }, // 移除临时字段 { $unset: 'matchedCity' } ]);
补充说明
- 方法一逻辑简单,适合大多数常规场景;方法二减少了数据库请求次数,适合复杂查询场景。
- 如果你只是想根据ID查询单个Restroom并填充完整地址,正确的
populate写法是:
RestroomModel.findOne({ _id: id }) .populate('fullAddress.address') .populate('fullAddress.city') .populate('fullAddress.region');
这样会自动填充关联文档的所有字段,无需单独指定street、zipCode等字段。
内容的提问来源于stack exchange,提问作者Estébaliz Martín
相关产品推荐
相关产品推荐

