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

Node.js + Mongoose实现MongoDB三级嵌套数据精准查询

Node.js + Mongoose实现MongoDB三级嵌套数据精准查询

嗨,我来帮你搞定这个三级嵌套数据的查询需求!根据你提供的文档结构和查询条件,我们可以用两种简洁的方式实现,直接返回你想要的wards数组。

首先先确认你的Mongoose模型定义(如果还没定义的话),这里我先给出对应文档结构的模型示例:

const mongoose = require('mongoose');

// 定义 ward 子文档 schema
const wardSchema = new mongoose.Schema({
  id: String,
  name: String
});

// 定义 district 子文档 schema
const districtSchema = new mongoose.Schema({
  id: String,
  name: String,
  wards: [wardSchema]
});

// 定义顶级文档 schema
const areaSchema = new mongoose.Schema({
  _id: mongoose.Schema.Types.ObjectId,
  name: String,
  code: String,
  district: [districtSchema]
});

// 创建模型
const Area = mongoose.model('Area', areaSchema);

方法一:使用findOne配合投影(Projection)

这种方法适合简单的嵌套查询,通过投影精准提取目标数据,代码更简洁:

async function getTargetWards() {
  try {
    // 你的查询条件参数
    const targetAreaId = '5f68c2b904f588d426ec8ce2';
    const targetDistrictId = '1';

    // 查询匹配的文档,仅提取符合条件的district下的wards
    const matchedArea = await Area.findOne(
      { 
        _id: mongoose.Types.ObjectId(targetAreaId), 
        'district.id': targetDistrictId 
      },
      { 'district.$.wards': 1, _id: 0 } // 投影规则:只保留第一个匹配的district的wards,隐藏_id
    );

    // 处理结果,提取最终的wards数组(兼容查询不到的情况)
    const targetWards = matchedArea?.district[0]?.wards || [];
    console.log(targetWards);
    return targetWards;
  } catch (error) {
    console.error('查询失败:', error);
    throw error;
  }
}

// 调用查询函数
getTargetWards();

代码说明:

  • findOne的第一个参数同时匹配顶级文档的_id和嵌套的district.id,确保定位到正确的父文档和目标district;
  • 投影参数里的district.$中的$是MongoDB的位置操作符,用来返回数组中第一个匹配条件的元素;
  • 最后从返回的结果中取出wards数组,并用可选链操作符避免查询不到时的报错。

方法二:使用聚合管道(Aggregation Pipeline)

如果后续需要更复杂的嵌套数据处理,聚合管道会更灵活,步骤更清晰:

async function getWardsWithAggregation() {
  try {
    const targetAreaId = '5f68c2b904f588d426ec8ce2';
    const targetDistrictId = '1';

    const aggregationResult = await Area.aggregate([
      // 1. 匹配指定顶级文档
      { $match: { _id: mongoose.Types.ObjectId(targetAreaId) } },
      // 2. 拆分数组,将每个district单独作为文档
      { $unwind: '$district' },
      // 3. 匹配目标district
      { $match: { 'district.id': targetDistrictId } },
      // 4. 只保留wards字段
      { $project: { wards: '$district.wards', _id: 0 } },
      // 5. 将wards数组拆分为单个元素(可选,按需使用)
      { $unwind: '$wards' },
      // 6. 重新组合成wards数组
      { $group: { _id: null, wards: { $push: '$wards' } } },
      // 7. 隐藏_id字段,只返回wards数组
      { $project: { _id: 0, wards: 1 } }
    ]);

    // 提取最终结果
    const targetWards = aggregationResult[0]?.wards || [];
    console.log(targetWards);
    return targetWards;
  } catch (error) {
    console.error('聚合查询失败:', error);
    throw error;
  }
}

// 调用聚合查询函数
getWardsWithAggregation();

代码说明:

  • 聚合管道通过分步操作,先定位顶级文档,再拆分嵌套数组,匹配目标district,最后提取并整理成你需要的wards数组;
  • 如果不需要对单个ward做额外处理,可以去掉$unwind和$group步骤,直接从aggregationResult[0].wards获取结果。

注意事项:

  • 记得将字符串类型的targetAreaId转换为mongoose.Types.ObjectId,因为你的文档_id是ObjectId类型;
  • 所有异步操作都用async/await处理,保证代码的可读性和错误捕获能力。

备注:内容来源于stack exchange,提问作者cuongnd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 12:18:03