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

MongoDB嵌套聚合查询:补全用户曲目信息并拉取同分类关联曲目方案咨询

MongoDB 高性能查询实现方案

前置性能优化(必做)

首先建立以下索引保障查询效率:

  • tracks集合:_id 默认索引已存在,若按创建时间排序需确保对createdAt(替换为你实际的时间字段名)建立索引
  • users集合:_id 默认索引已存在
  • categories集合:_id 默认索引已存在

实现逻辑说明

在原有聚合的基础上扩展两个嵌套lookup实现需求,全程走索引避免全表扫描:

  1. 原有关联creator的lookup内部新增嵌套lookup,将creator的tracks数组ID转成完整曲目对象,截取最近5条并剔除creator字段
  2. 新增一层关联categories的lookup,拿到分类下所有曲目ID后过滤当前查询曲目,再关联tracks集合取最新5条并剔除creator字段

完整聚合代码

const targetTrackId = ObjectId(trackId); // 提前转好ObjectId避免重复转换

const result = await tracks.aggregate([
  // 第一步:匹配目标曲目
  {
    $match: { _id: targetTrackId },
  },
  // 第二步:关联创作者,同时处理创作者的曲目列表
  {
    $lookup: {
      let: { userId: { $toObjectId: "$creatorId" } },
      from: "users",
      pipeline: [
        { $match: { $expr: { $eq: ["$_id", "$$userId"] } } },
        // 截取最新的5条曲目ID
        { $addFields: { tracks: { $slice: ["$tracks", -5] } } },
        // 关联tracks集合拿到完整曲目信息
        {
          $lookup: {
            let: { trackIds: { 
              $map: { input: "$tracks", in: { $toObjectId: "$$this" } } 
            } },
            from: "tracks",
            pipeline: [
              { $match: { $expr: { $in: ["$_id", "$$trackIds"] } } },
              // 按创建时间倒序,确保是最新的5条
              { $sort: { createdAt: -1 } },
              // 剔除creator字段
              { $unset: "creator" }
            ],
            as: "tracks"
          }
        }
      ],
      as: "creator",
    },
  },
  // 把creator从数组转成对象
  { $unwind: "$creator" },
  // 第三步:关联分类获取同分类相关曲目
  {
    $lookup: {
      let: { categoryId: { $toObjectId: "$categoryId" }, currentTrackId: targetTrackId },
      from: "categories",
      pipeline: [
        { $match: { $expr: { $eq: ["$_id", "$$categoryId"] } } },
        // 过滤掉当前查询的曲目ID
        {
          $addFields: {
            tracks: {
              $filter: {
                input: "$tracks",
                cond: { $ne: [ { $toObjectId: "$$this" }, "$$currentTrackId" ] }
              }
            }
          }
        },
        // 截取最新的最多5条ID
        { $addFields: { tracks: { $slice: ["$tracks", -5] } } },
        // 关联tracks拿完整信息
        {
          $lookup: {
            let: { trackIds: { 
              $map: { input: "$tracks", in: { $toObjectId: "$$this" } } 
            } },
            from: "tracks",
            pipeline: [
              { $match: { $expr: { $in: ["$_id", "$$trackIds"] } } },
              { $sort: { createdAt: -1 } },
              { $unset: "creator" }
            ],
            as: "tracks"
          }
        },
        // 只返回tracks字段
        { $project: { tracks: 1, _id: 0 } }
      ],
      as: "relatedTracks"
    }
  },
  // 把relatedTracks从嵌套结构提出来
  { $unwind: "$relatedTracks" },
  { $addFields: { relatedTracks: "$relatedTracks.tracks" } },
  { $limit: 1 }
]).toArray();

注意事项

  • 如果你存储的ID本身就是ObjectId类型,可以去掉所有$toObjectId转换步骤,性能会更高
  • 代码中的createdAt替换成你实际存储曲目创建时间的字段名,如果你的users.tracks和categories.tracks数组本身就是按最新插入顺序排列的,也可以省略lookup内部的sort步骤,性能更优
  • 所有匹配都走单文档命中+索引查询,无全表扫描,性能符合高并发场景要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 07:06:04