You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 05:30:05