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

合并MongoDB populate返回的嵌套数组并去重的实现方案

MongoDB嵌套访客数组合并去重方案

需求说明

需要将MongoDB populate操作返回的嵌套访客数组合并为一维数组,同时按照id去除重复项,支持MongoDB原生聚合或纯JS两种实现方式。

原始嵌套数组结构

"visitors": [
    [
        {
            "name": "matan",
            "id": "61793e6a0e08cdcaf213c0b1"
        },
        {
            "name": "shani",
            "id": "61793e910e08cdcaf213c0b5"
        }
    ],
    [
        {
            "name": "david",
            "id": "6179869cb4944c6b19b05a23"
        },
        {
            "name": "orit",
            "id": "617986e535fdf4942ef659bd"
        }
    ],
    [
        {
            "name": "david",
            "id": "6179869cb4944c6b19b05a23"
        },
        {
            "name": "orit",
            "id": "617986e535fdf4942ef659bd"
        }
    ]
]

预期输出结构

"visitors": [
    {
        "name": "matan",
        "id": "61793e6a0e08cdcaf213c0b1"
    },
    {
        "name": "shani",
        "id": "61793e910e08cdcaf213c0b5"
    },
    {
        "name": "david",
        "id": "6179869cb4944c6b19b05a23"
    },
    {
        "name": "orit",
        "id": "617986e535fdf4942ef659bd"
    }
]

业务背景

实际业务为查询单个太阳系下的所有访客,数据关联层级为 solars > planets > visitors,三个集合的Schema定义如下:

const solarsModel = new Schema({
    planets: [ { type: Schema.Types.ObjectId ,ref:'planet'} ],
    starName: { type: String, required: true, default: "" }
})

const planetModel = new Schema({
    planetName: { type: String, required: true, default: "" },
    system:{type: Schema.Types.ObjectId, ref: 'solar'},
    visitors: [{ type: Schema.Types.ObjectId , ref: 'visitor'}]
})

const visitorModel = new Schema({
    visitorName:{ type: String, required: true, default: "" },
    homePlanet: {type: Schema.Types.ObjectId, ref:"planet" },
    visitedPlanets: [{ type: Schema.Types.ObjectId, ref:"planet" }]
})

此前使用多层populate查询得到嵌套数组结果,代码如下:

const response = await solarModel
  .findById({ _id: data.id })
  .select({ starName: 1, _id: 0 })
  .populate({
    path: "planets",
    select: { visitors: 1, _id: 0 },
    populate: {
      path: "visitors",
      select: "visitorName",
    },
  })
  .exec();

实现方案

方案1:纯JS直接处理返回结果

如果不需要修改查询逻辑,可直接对populate返回的嵌套数组做降维去重处理:

// visitors为populate返回的嵌套数组
const uniqueVisitors = [...new Map(
  visitors.flat().map(item => [item.id, item])
).values()];

逻辑说明:先用flat()将二维数组降为一维,再通过Map按访客id去重,最后转为数组即可得到结果。

方案2:MongoDB聚合查询实现

直接在数据库层面通过聚合管道完成关联、合并、去重操作,性能更优:

exports.findVisitorSystemHandler = async (data) => {
  const systemName = await solarModel.findById({ _id: data.id });
  const response = await planetModel.aggregate([
    // 匹配当前太阳系下的所有行星
    { $match: { system: makeObjectId(data.id) } },
    // 关联访客表拉取访客信息
    {
      $lookup: {
        from: "visitors",
        localField: "visitors",
        foreignField: "_id",
        as: "solarVisitors",
      },
    },
    // 过滤不需要返回的访客字段
    {
      $project: {
        solarVisitors: {
          visitedPlanets: 0,
          homePlanet: 0,
          __v: 0,
        },
      },
    },
    // 拆分数组得到单个访客对象
    { $unwind: "$solarVisitors" },
    // 分组去重,合并所有访客
    {
      $group: {
        _id: null,
        system: { $addToSet: systemName.starName },
        solarVisitors: {
          $addToSet: {
            id: "$solarVisitors._id",
            name: "$solarVisitors.visitorName",
          },
        },
      },
    },
    // 拆解星系名称数组
    { $unwind: "$system" },
    // 过滤不需要返回的_id字段
    {
      $project: {
        _id: 0,
      },
    },
  ]);
  return response;
};

内容的提问来源于stack exchange,提问作者stephan bazbaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 06:39:01