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

如何在Mongoose/MongoDB中返回单个嵌套任务对象

问题:根据任务ID从嵌套数组中获取单个任务对象

数据库文档结构

{
  "_id": "62fa5aa25778ec97bc6ee231",
  "user": "62f0eb5ebebd0f236abcaf9d",
  "name": "Marketing Plan",
  "columns": [
    {
      "name": "todo",
      "_id": "62fa5aa25778ec97bc6ee233",
      "tasks": [
        {
          "title": "Task Four testing 2",
          "description": "This is task four",
          "subtasks": [
            {
              "name": "wash dshes test",
              "completed": false,
              "_id": "62ff74bfe80b11ade2d34456"
            },
            {
              "name": "do homework",
              "completed": false,
              "_id": "62ff74bfe80b11ade2d34457"
            }
          ],
          "_id": "62ff74bfe80b11ade2d34455"
        }
      ]
    },
    {
      "name": "doing",
      "_id": "62fa5aa25778ec97bc6ee234",
      "tasks": []
    },
    {
      "name": "done",
      "_id": "62fa5aa25778ec97bc6ee235",
      "tasks": []
    }
  ],
  "__v":0
}

预期需求

根据req.params.id返回对应的单个任务对象,例如ID为62ff74bfe80b11ade2d34455的任务,预期返回结果:

{
  "title": "Task Four testing 2",
  "description": "This is task four",
  "subtasks": [
    {
      "name": "wash dshes test",
      "completed": false,
      "_id": "62ff74bfe80b11ade2d34456"
    },
    {
      "name": "do homework",
      "completed": false,
      "_id": "62ff74bfe80b11ade2d34457"
    }
  ],
  "_id": "62ff74bfe80b11ade2d34455"
}

现有代码问题

使用aggregate框架编写的代码在Postman测试时无响应,代码如下:

const getTask = asyncHandler(async (req, res) => {
  const task = await Board.aggregate([
    {
      $match: {
        "columns.tasks._id": req.params.id,
      },
    },
    {
      $project: {
        columns: {
          $first: {
            $filter: {
              input: "$columns.tasks",
              cond: {
                $eq: ["$$this._id", req.params.id],
              },
            },
          },
        },
      },
    },
    {
      $replaceRoot: {
        newRoot: "$columns",
      },
    },
  ]);
});

问题分析与解决方案

问题点

  1. 未返回响应:代码中没有调用res.json()或res.send()向客户端返回结果,导致请求一直处于挂起状态
  2. 嵌套数组处理错误:$filter的input参数错误,$columns是数组,每个元素包含tasks数组,直接用$columns.tasks无法正确遍历嵌套结构
  3. 类型不匹配:req.params.id是字符串类型,而数据库中_id是ObjectId类型,直接比较会匹配失败

修正后的代码方案一(使用aggregate展开数组)

const { ObjectId } = require('mongoose');
const getTask = asyncHandler(async (req, res) => {
  const taskId = new ObjectId(req.params.id);
  const result = await Board.aggregate([
    // 匹配包含目标任务的Board文档
    { $match: { "columns.tasks._id": taskId } },
    // 展开columns数组,将每个column作为单独文档
    { $unwind: "$columns" },
    // 展开当前column下的tasks数组
    { $unwind: "$columns.tasks" },
    // 精准匹配目标任务
    { $match: { "columns.tasks._id": taskId } },
    // 将任务对象作为根文档返回
    { $replaceRoot: { newRoot: "$columns.tasks" } },
    // 只取第一个匹配结果(确保返回单个任务)
    { $limit: 1 }
  ]);

  if (result.length === 0) {
    return res.status(404).json({ message: "任务不存在" });
  }

  // 返回目标任务
  res.json(result[0]);
});

修正后的代码方案二(使用findOne结合投影)

如果不想使用aggregate,也可以用findOne配合投影操作:

const { ObjectId } = require('mongoose');
const getTask = asyncHandler(async (req, res) => {
  const taskId = new ObjectId(req.params.id);
  // 查询包含目标任务的Board,并投影提取出目标任务
  const board = await Board.findOne(
    { "columns.tasks._id": taskId },
    { 
      targetTask: {
        $reduce: {
          input: "$columns",
          initialValue: null,
          in: {
            $cond: [
              // 判断当前column是否包含目标任务
              { $ne: [{ $filter: { input: "$$this.tasks", cond: { $eq: ["$$this._id", taskId] } } , []] },
              // 提取当前column中的目标任务
              { $first: { $filter: { input: "$$this.tasks", cond: { $eq: ["$$this._id", taskId] } } },
              // 保留之前找到的任务(如果有的话)
              "$$value"
            ]
          }
        }
      }
    }
  );

  if (!board || !board.targetTask) {
    return res.status(404).json({ message: "任务不存在" });
  }

  res.json(board.targetTask);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 21:57:32