【问题标题】:How to get the aggregation values grouped by group names in mongodb using node.js?如何使用node.js在mongodb中获取按组名分组的聚合值?
【发布时间】:2020-01-08 21:56:17
【问题描述】:

我有一个用例,我有 3 个集合。即每个模板的模板、组和 1-动态集合,它们将在模板创建后立即创建。

每个templatedevices 组成,每个device 由一个groupId 组集合组成。动态集合存储模板设备推送的数据。

现在我需要找出 Groups 集合的设备grouped by groupName 的聚合(总和)值。

以下是我收藏的样本数据。

模板数据

{
  "_id": "5e0ae38729218b0a3861118b",
  "templateId": "27127206822",
  "devices": [
    {
      "deviceId": "waterTest",
      "_id": "5e0ae49629218b0a3861118f",
      "group": "5e0ae41d29218b0a3861118d",
    },{
       "deviceId": "Test",
       "_id": "5e0af166981f39410cd89b72",
       "group": "5e0af11d981f39410cd89b70"
    }]
}

动态收集数据

[
  {
    "_id": "5e0ae793b1384737a4f855cf",
    "template": "27127206822",
    "deviceId": "waterTest",
    "heat" : 20,
    "humidity" : 10
   },{
      "_id": "5e0ae7a2b1384737a4f855d0",
      "template": "27127206822",
      "deviceId": "waterTest",
      "heat" : 40,
      "humidity" : 20
   },{
      "_id": "5e0ae890b1384737a4f855d3",
      "template": "27127206822",
      "deviceId": "waterTest",
      "heat" : 60,
      "humidity" : 50
    },{
       "_id": "5e0af188981f39410cd89b73",
       "template": "27127206822",
       "deviceId": "Test",
       "heat": 60,
       "humidity": 50
   },{
      "_id": "5e0af196981f39410cd89b74",
      "template": "27127206822",
      "deviceId": "Test",
      "heat": 10,
      "humidity": 20
   }]

组数据

[{
   "_id": "5e0af11d981f39410cd89b70",
   "template": "5e0ae38729218b0a3861118b",
   "groupName": "Flats"
 },{
    "_id": "5e0ae41d29218b0a3861118d",
    "template": "5e0ae38729218b0a3861118b",
    "groupName": "SPool"
 }]

现在看看我到目前为止写的聚合查询。

let templateId = "27127206822"; // Dynamic Collection

[err, templateData] = await to(mongoose.connection.db.collection(templateId)
  .aggregate([
     {
          $lookup:{
             from:"templates",
             localField:"template",
             foreignField:"templateId",
             as:"template"
          }
      },{ 
          $unwind:"$template"
      },{ 
          $unwind:"$template.devices"
      },{
          $lookup:{
             from:"groups",
             localField:"template.devices.group",
             foreignField:"_id",
             as:"group"
          }
      },{
          $unwind:"$group"
      },{
          $group:{
             _id: "$groupData.groupName",
             heat:{$sum:"$heat"},
             humidity:{$sum:"$humidity"},
             count:{$sum:1}
          }
      }]));

现在,我需要得到每个 device 的总和,每个 device 由 Group 集合的 groupName 分组。但我得到了错误的数据。即,一个组的总和也被添加到所有其他组中

**返回的输出**

//Am getting this Data
[
  {
    "_id": "Flats",
    "heat": 190,  // 2 group's data getting added in both the groups
    "humidity": 150,
    "count":5
  },{
    "_id": "SPool",
    "heat": 190,
    "humidity": 150,
    "count":5
  }]

预期输出

[
  {
    "_id": "Flats",
    "heat": 70,
    "humidity": 70,
    "count":2
  },{
    "_id": "SPool",
    "heat": 120,
    "humidity": 80,
    "count":3
  }]

为了获得所需的结果,我有什么遗漏的吗?

【问题讨论】:

  • 你为什么要转至$lookup本地template和国外templateId?我看不出有任何方法可以匹配 "13435158964" 和动态集合中的任何值。

标签: javascript node.js mongodb mongoose


【解决方案1】:

您可以添加$group 作为下一个聚合阶段,并使用$sum 进行计数和累加:

{
    $group: {
        _id: "$group.groupName",
        "count": { $sum: 1 },
        "heat": { $sum: "$heat" },
        "humidity": { $sum: "$humidity" }
    }
}

【讨论】:

  • 我已经使用它并且工作正常。但是每组都得到相同的结果。像这样,[ { "_id": "Pools", "heat": 1498, "humidity": 3924 }, { "_id": "Flat", "heat": 1498, "humidity": 3924 }, { "_id": "Swimming Pool", "heat": 1498, "humidity": 3924 }, { "_id": "Common Area", "heat": 1498, "humidity": 3924 } ]
  • @Aravind 他们都指的是同一个模板吗?你需要调试你的管道 - 我会先从$lookup 开始,看看你是否得到了预期的结果,添加下一个阶段等
  • 是的,@mickl。它们都引用同一个模板。我想,我发现了这个问题。实际上,每个组的数据都被添加到所有组中。但是如何在求和的同时区分组名呢?
  • @Aravind 你能编辑你的问题并展示这种情况的例子吗?
  • @Aravind 我猜您从多个组中获取数据,因为您按groupName 分组,更好的方法是将groupName 替换为_id并将groupName: { $first: "$groupName" } 添加到$group 阶段
【解决方案2】:

更新

我解决了这个问题。一旦$unwind:"$template.devices" 完成,每个文档都会获得$template.devices 数组的每个设备,并且该文档会被复制。

所以为了得到正确的答案,我们需要将deviceId 与每个文档的deviceId of template.devices 对象进行匹配。

查询将是,

[err, templateData] = await to(mongoose.connection.db.collection(templateId)
  .aggregate([
     {
          $lookup:{
             from:"templates",
             localField:"template",
             foreignField:"templateId",
             as:"template"
          }
      },{ 
          $unwind:"$template"
      },{ 
          $unwind:"$template.devices"
      },{
          $match:{
            $expr:{
              $eq: [ "$deviceId","$template.devices.deviceId" ]
            }
          }
      },{
          $lookup:{
             from:"groups",
             localField:"template.devices.group",
             foreignField:"_id",
             as:"group"
          }
      },{
          $unwind:"$group"
      },{
          $group:{
             _id: "$groupData.groupName",
             heat:{$sum:"$heat"},
             humidity:{$sum:"$humidity"},
             count:{$sum:1}
          }
      }]));

通过使用它,我们将获得预期的输出。也就是说,

[
  {
    "_id": "Flats",
    "heat": 70,
    "humidity": 70,
    "count":2
  },{
    "_id": "SPool",
    "heat": 120,
    "humidity": 80,
    "count":3
  }]

【讨论】:

    猜你喜欢
    • 2021-03-18
    • 2016-07-03
    • 2015-03-28
    • 2021-03-24
    • 2021-07-27
    • 2021-05-19
    • 2013-11-25
    • 1970-01-01
    • 2019-05-19
    相关资源
    最近更新 更多