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

如何在Mongoose与Node.js中从数组生成对象用于MongoDB聚合

处理动态字段数组并生成MongoDB聚合$group中的Sum字段(过滤指定字段)

首先,咱们先理清你遇到的核心问题:你需要从动态字段数组中过滤掉不区分大小写的timeStamp和deviceId,然后把剩下的字段转换成MongoDB聚合$group阶段需要的字段名: { $sum: "$字段名" }格式,最终整合到聚合查询里。你的现有代码有几个逻辑和写法上的问题,我帮你一步步修正:

现有代码的问题分析

  1. 过滤条件逻辑错误:你用了!data.name.match(/time/g) || !data.name.match(/deviceId/g),这个逻辑会导致只要不匹配其中一个就保留,刚好和你要排除这两个字段的需求相反,而且正则没有加不区分大小写的标志,匹配不够准确。
  2. 不必要的async forEach:这里没有异步操作,async会导致遍历过程无法同步执行(forEach本身也不支持异步等待),可能导致vList没有正确填充。
  3. 错误的字符串拼接与解析:你把聚合字段拼成字符串再JSON.parse,最后得到的是字符串数组,没法直接插入$group对象中,完全没必要绕这个弯。

修正后的完整解决方案

第一步:过滤不需要的字段

用filter和map组合,结合不区分大小写的匹配,简洁高效地筛选出需要的字段:

const jsonObj = [ 
  { name: "heat", value: "HEAT" }, 
  { name: "humidity", value: "HUMIDITY" }, 
  { name: "deviceId", value: "DEVICEID" }, 
  { name: "timeStamp", value: "TIMESTAMP" } 
];

// 定义要排除的字段(转成小写,方便不区分大小写匹配)
const excludedFields = new Set(['timestamp', 'deviceid']);

// 过滤出需要参与聚合的字段名
const targetFields = jsonObj
  .map(item => item.name)
  .filter(fieldName => !excludedFields.has(fieldName.toLowerCase()));

第二步:生成$group需要的聚合配置

直接构建一个对象,每个键是字段名,值是对应的$sum聚合规则,不需要任何字符串操作:

const groupSumFields = {};
targetFields.forEach(field => {
  groupSumFields[field] = { $sum: `$${field}` };
});

第三步:整合到MongoDB聚合查询中

用对象扩展运算符...把生成的聚合字段直接合并到$group阶段:

db.collection(templateId).aggregate([
  { 
    $match: { 
      entryDayTime: { 
        $lt: new Date(lastDay), 
        $gte: new Date(firstDay) 
      } 
    } 
  },
  { 
    $group: {
      _id: "$deviceId",
      Count: { $sum: 1 },
      // 直接扩展生成的sum字段
      ...groupSumFields
    } 
  },
  { $sort: { entryDayTime: -1 } }
]);

效果验证

最终生成的groupSumFields会是这样的对象:

{
  heat: { $sum: "$heat" },
  humidity: { $sum: "$humidity" }
}

完美匹配你需要的$group阶段格式,而且自动排除了timeStamp和deviceId字段,不需要再处理字符串的单引号问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:07:24