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

如何跨MongoDB集合查询,按用户+日期返回指定组织的指标文档

解决MongoDB跨集合聚合按「用户+日期」返回文档的问题

问题背景

我们需要跨MongoDB的users、daily_metrics、userspaces(记录用户所属组织)集合进行查询,获取指定组织下用户的指标文档并附带用户详情,要求按「用户+localDate」分别返回文档,而非将同一用户的所有指标合并为单文档。

当前问题

当前基于daily_metrics的聚合管道会将同一用户的所有指标聚合为单文档,仅保留首个localDate,不符合需求。不确定是否使用了正确的聚合阶段/累加器,或是否在错误阶段执行了$unwind操作。

现有聚合管道

[
  {
    $lookup: {
      from: "userspaces",
      localField: "user",
      foreignField: "user",
      as: "userspaces",
    },
  },
  {
    $lookup: {
      from: "users",
      localField: "user",
      foreignField: "_id",
      as: "userdetails",
    },
  },
  {
    $unwind: "$userspaces",
  },
  {
    $match: {
      createdAt: {
        $gte: ISODate("2023-03-09T18:30:00.000Z"),
        $lt: ISODate("2023-03-30T18:30:00.000Z"),
      },
      "userspaces.organization": ObjectId(
        "63fdb56aac3a6db93dcbbc22"
      ),
    },
  },
  {
    $group: {
      _id: "$user",
      name: {
        $first: "$userdetails.name",
      },
      dp: {
        $first: "$userdetails.profile_image",
      },
      handle: {
        $first: "$userdetails.profile_id",
      },
      date: {
        $first: "$localDate",
      },
      steps: {
        $sum: "$metrics.steps",
      },
      distance: {
        $sum: "$metrics.distance",
      },
      calories: {
        $sum: "$metrics.calories",
      },
    },
  },
  {
    $sort: {
      name: 1,
    },
  },
]

样本文档

daily_metrics

{
  "_id": {
    "$oid": "640a7f519b12b8a960362e33"
  },
  "user": {
    "$oid": "6408109bac3a6db93dcbe03d"
  },
  "metrics": {
    "steps": 6911,
    "calories": 463.63,
    "distance": 3870.62
  },
  "localDate": "03-10-2023",
  "createdAt": {
    "$date": {
      "$numberLong": "1678409553242"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1678512627838"
    }
  },
  "__v": 0
}

userspaces

{
  "_id": {
    "$oid": "620158cc4b23c40d3457c0c1"
  },
  "organization": {
    "$oid": "6200f8aa4b23c40d3457c0a9"
  },
  "user": {
    "$oid": "61f0fd1eb3dea2d99c6f9658"
  },
  "createdAt": {
    "$date": {
      "$numberLong": "1644255436192"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1644255436192"
    }
  },
  "__v": 0
}

users

{
  "_id": {
    "$oid": "61ee66c227b40d7b5fc912e4"
  },
  "verified": true,
  "name": "Amanchira",
  "email": "amanchirasdf96@gmail.com",
  "profile_image": "https://d25ji.cloudfront.net/profileimages/asfsefkze.jpg",
  "createdAt": {
    "$date": {
      "$numberLong": "1643013826921"
    }
  },
  "updatedAt": {
    "$date": {
      "$numberLong": "1659381101772"
    }
  },
  "__v": 0,
  "profile_id": "amanchira1"
}

预期输出

{
  "_id": {
    "$oid": "640835b4ac3a6db93dcbe187"
  },
  "name": [
    "Adeanlika"
  ],
  "dp": [],
  "handle": [
    "adeanlika"
  ],
  "date": "03-10-2023",
  "steps": 17635.25,
  "distance": 13819,
  "calories": 692.4
}

解决方案

问题核心在于$group阶段的_id只按user分组,导致同一用户的所有日期指标被合并。修改思路如下:

  1. 调整分组键:将$group的_id改为包含user和localDate的复合键,确保每个「用户+日期」组合单独成文档。
  2. 优化$unwind时机:对userdetails执行$unwind,避免返回数组格式的用户信息(最后通过$project转为预期的数组格式)。
  3. 修正字段提取:使用$first获取用户详情(同一分组内用户信息一致)。

修改后的聚合管道:

[
  // 关联用户所属组织
  {
    $lookup: {
      from: "userspaces",
      localField: "user",
      foreignField: "user",
      as: "userspaces"
    }
  },
  // 关联用户详情
  {
    $lookup: {
      from: "users",
      localField: "user",
      foreignField: "_id",
      as: "userdetails"
    }
  },
  // 展开组织关联结果,便于后续匹配
  {
    $unwind: "$userspaces"
  },
  // 展开用户详情,避免数组格式
  {
    $unwind: "$userdetails"
  },
  // 筛选指定组织和时间范围的记录
  {
    $match: {
      createdAt: {
        $gte: ISODate("2023-03-09T18:30:00.000Z"),
        $lt: ISODate("2023-03-30T18:30:00.000Z")
      },
      "userspaces.organization": ObjectId("63fdb56aac3a6db93dcbbc22")
    }
  },
  // 按「用户+日期」分组,聚合当日指标
  {
    $group: {
      _id: {
        user: "$user",
        date: "$localDate"
      },
      name: { $first: "$userdetails.name" },
      dp: { $first: "$userdetails.profile_image" },
      handle: { $first: "$userdetails.profile_id" },
      steps: { $sum: "$metrics.steps" },
      distance: { $sum: "$metrics.distance" },
      calories: { $sum: "$metrics.calories" }
    }
  },
  // 重塑文档结构,匹配预期输出格式
  {
    $project: {
      _id: "$_id.user",
      date: "$_id.date",
      name: ["$name"],
      dp: ["$dp"],
      handle: ["$handle"],
      steps: 1,
      distance: 1,
      calories: 1
    }
  },
  // 按用户名排序
  {
    $sort: { name: 1 }
  }
]

关键修改说明

  • 复合分组键:_id: { user: "$user", date: "$localDate" }确保每个用户的每日指标单独成文档,不会被合并。
  • $unwind用户详情:将userdetails数组展开为单个对象,方便分组时提取字段,最后通过$project转为预期的数组格式。
  • $project重塑结构:把日期从分组_id中提取到顶层字段,完全匹配预期输出的文档结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 01:30:01