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

MongoDB集合中文档内数组按频率排序及求众值方案问询

高效解决方案:用$reduce统计数组元素频率,避免Unwind

针对你的场景(每个数组含5万+元素,MongoDB 5.0.22无内置mode函数),核心思路是在数组内部直接统计频率,避免对超大数组执行$unwind(该操作会生成大量中间文档,严重拖慢性能)。具体通过$reduce完成单数组内的计数,再通过分组合并同color的统计结果,最终提取最高频元素。

步骤1:单文档内统计各数组的元素频率

先对每个文档的fruit、vegetable、meat数组分别做频率统计,生成「元素:计数」的键值对对象:

db.collection.aggregate([
  {
    $project: {
      color: 1,
      // 统计fruit数组的元素频率
      fruit_counts: {
        $reduce: {
          input: "$fruit",
          initialValue: {},
          in: {
            $mergeObjects: [
              "$$value",
              {
                $arrayToObject: [[
                  "$$this",
                  { $add: [ { $ifNull: [ "$$value.$$this", 0 ] }, 1 ] }
                ]]
              }
            ]
          }
        }
      },
      // 统计vegetable数组的元素频率
      vegetable_counts: {
        $reduce: {
          input: "$vegetable",
          initialValue: {},
          in: {
            $mergeObjects: [
              "$$value",
              {
                $arrayToObject: [[
                  "$$this",
                  { $add: [ { $ifNull: [ "$$value.$$this", 0 ] }, 1 ] }
                ]]
              }
            ]
          }
        }
      },
      // 统计meat数组的元素频率
      meat_counts: {
        $reduce: {
          input: "$meat",
          initialValue: {},
          in: {
            $mergeObjects: [
              "$$value",
              {
                $arrayToObject: [[
                  "$$this",
                  { $add: [ { $ifNull: [ "$$value.$$this", 0 ] }, 1 ] }
                ]]
              }
            ]
          }
        }
      }
    }
  },

步骤2:按color分组,合并同color的统计结果

将同一color下所有文档的频率统计值累加,得到该color对应的全局元素计数:

{
    $group: {
      _id: "$color",
      // 累加fruit的全局计数
      fruit_totals: {
        $mergeObjects: {
          $arrayToObject: {
            $map: {
              input: { $objectToArray: "$fruit_counts" },
              as: "item",
              in: {
                k: "$$item.k",
                v: { $add: [ "$$item.v", { $ifNull: [ "$fruit_totals.$$item.k", 0 ] } ] }
              }
            }
          }
        }
      },
      // 累加vegetable的全局计数
      vegetable_totals: {
        $mergeObjects: {
          $arrayToObject: {
            $map: {
              input: { $objectToArray: "$vegetable_counts" },
              as: "item",
              in: {
                k: "$$item.k",
                v: { $add: [ "$$item.v", { $ifNull: [ "$vegetable_totals.$$item.k", 0 ] } ] }
              }
            }
          }
        }
      },
      // 累加meat的全局计数
      meat_totals: {
        $mergeObjects: {
          $arrayToObject: {
            $map: {
              input: { $objectToArray: "$meat_counts" },
              as: "item",
              in: {
                k: "$$item.k",
                v: { $add: [ "$$item.v", { $ifNull: [ "$meat_totals.$$item.k", 0 ] } ] }
              }
            }
          }
        }
      }
    }
  },

步骤3:提取各分类的最高频元素

将全局计数的键值对对象转为数组,按计数降序排序后取第一个元素,即为该color下对应分类的最高频项:

{
    $project: {
      color: "$_id",
      _id: 0,
      top_fruit: {
        $arrayElemAt: [
          { $sortArray: {
            input: { $objectToArray: "$fruit_totals" },
            sortBy: { v: -1 }
          }},
          0
        ]
      },
      top_vegetable: {
        $arrayElemAt: [
          { $sortArray: {
            input: { $objectToArray: "$vegetable_totals" },
            sortBy: { v: -1 }
          }},
          0
        ]
      },
      top_meat: {
        $arrayElemAt: [
          { $sortArray: {
            input: { $objectToArray: "$meat_totals" },
            sortBy: { v: -1 }
          }},
          0
        ]
      }
    }
  },
  // 可选:格式化输出,只保留元素名和计数
  {
    $project: {
      color: 1,
      top_fruit: {
        item: "$top_fruit.k",
        count: "$top_fruit.v"
      },
      top_vegetable: {
        item: "$top_vegetable.k",
        count: "$top_vegetable.v"
      },
      top_meat: {
        item: "$top_meat.k",
        count: "$top_meat.v"
      }
    }
  }
])

性能说明

  • 避免了$unwind操作:$reduce在数组内部完成统计,无需将5万+元素拆分为单个文档,大幅减少中间数据量。
  • 时间复杂度优化:单数组统计为O(n),分组合并为O(m)(m为同color的文档数),整体性能远优于$unwind+$group的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 06:25:21