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

MongoDB:如何单次查询获取两个计数且结果不存于数组

解决方案:优化MongoDB关联查询实现点赞/踩数统计

针对你提到的三种需求,我分别给出对应的MongoDB查询调整方案,全部可以在单次查询内完成统计:

1. 直接返回简洁格式 {upvotes: 2, downvotes: 1}

你可以在$lookup的子管道里调整分组逻辑,用$cond条件求和直接拆分点赞和踩数,最后通过投影整理成你想要的简洁格式:

db.comments.aggregate([
  {
    $lookup: {
      from: "votesComments",
      as: "commentVotes",
      let: { commentI: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$commentId", "$$commentI"] } } },
        {
          $group: {
            _id: null,
            upvotes: { $sum: { $cond: [{ $eq: ["$up", 1] }, 1, 0] } },
            downvotes: { $sum: { $cond: [{ $eq: ["$up", 0] }, 1, 0] } }
          }
        }
      ]
    }
  },
  { $unwind: { path: "$commentVotes", preserveNullAndEmptyArrays: true } },
  {
    $project: {
      // 按需保留comments集合的原字段,比如内容、作者等
      content: 1,
      author: 1,
      upvotes: { $ifNull: ["$commentVotes.upvotes", 0] },
      downvotes: { $ifNull: ["$commentVotes.downvotes", 0] }
    }
  }
])

核心逻辑是在分组阶段就完成条件统计,用$ifNull处理没有投票记录的评论(返回0值,避免空数据),最终直接输出结构化的点赞/踩数字段。

2. 执行unwind后保留数组的两个元素

你之前unwind后只得到单个元素,大概率是没设置preserveNullAndEmptyArrays参数。调整后的查询会完整保留数组内的所有元素:

db.comments.aggregate([
  {
    $lookup: {
      from: "votesComments",
      as: "commentVotes",
      let: { commentI: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$commentId", "$$commentI"] } } },
        { "$group" : {_id:"$up", count:{$sum:1}} }
      ]
    }
  },
  { $unwind: { path: "$commentVotes", preserveNullAndEmptyArrays: true } }
])

如果commentVotes是包含两个元素的数组,unwind后会生成两个独立文档,分别对应up=1和up=0的统计结果;如果某个评论只有点赞或只有踩,数组会只有一个元素,unwind后也会保留该元素。

3. 单次查询统计up=1和down=1的数量(假设votesComments同时有up/down字段)

如果你的votesComments集合是用单独的up和down字段标记赞/踩(同一文档不会同时出现up=1和down=1),可以直接在分组阶段分别统计两类数据:

db.comments.aggregate([
  {
    $lookup: {
      from: "votesComments",
      as: "commentVotes",
      let: { commentI: "$_id" },
      pipeline: [
        { $match: { $expr: { $eq: ["$commentId", "$$commentI"] } } },
        {
          $group: {
            _id: null,
            upvotes: { $sum: { $cond: [{ $eq: ["$up", 1] }, 1, 0] } },
            downvotes: { $sum: { $cond: [{ $eq: ["$down", 1] }, 1, 0] } }
          }
        }
      ]
    }
  },
  { $unwind: { path: "$commentVotes", preserveNullAndEmptyArrays: true } },
  {
    $project: {
      // 保留原comments字段
      _id: 1,
      content: 1,
      upvotes: { $ifNull: ["$commentVotes.upvotes", 0] },
      downvotes: { $ifNull: ["$commentVotes.downvotes", 0] }
    }
  }
])

这个方案和第一种逻辑类似,只是把down字段的统计单独拆分,确保同时统计两种独立的投票类型。

补充小提示

如果你的业务逻辑是用up字段的1/0来区分赞/踩(和原查询一致),第一种方案是最推荐的——返回格式简洁,不需要后续额外处理,且性能最优。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:12:27