我有一个集合,每2秒 for each uID(这是主键)存储一次数据.现在我想查询每个uID的最后30个文档,并根据它们的索引号将它们分组.在这种情况下如何处理?如果我应用$limit,那么所有UID只返回30个文档.

db.getCollection("devices").aggregate(
    [
        { 
            "$match" : { 
                "uID" : { 
                    "$in" : [
                        "20200308", 
                        "20200306", 
                        "12345678"
                    ]
                }
            }
        }
    ], 
    { 
        "allowDiskUse" : false
    }
);

上面的查询将返回所有文档,如何将查询限制 for each uID 30个文档?此外,如果查询成功,如何对不同文档的所有数组索引进行分组,以便得到一个字段的值之和,该字段包含30个分组在一起的文档.例子:

[
    {
        _id: 0,  // index value of all array after grouping them.
        sumOfValuesFoundInArrayIndex: 100,
    },
    {
        _id: 1,
        sumOfValuesFoundInArrayIndex: 600,
    }
    .
    .
    .
    .
    {
        _id: 29,
        sumOfValuesFoundInArrayIndex: 600,
    }
]

JSON示例:

[
  {
    "timeStamp": 1644962269,
    "uID": "20200308",
    "capacityLeft": 500
  },
  {
    "timeStamp": 1644962272,
    "uID": "20200308",
    "capacityLeft": 499
  },
  {
    "timeStamp": 1644962275,
    "uID": "20200306",
    "capacityLeft": 300
  },
  {
    "timeStamp": 1644962277,
    "uID": "20200308",
    "capacityLeft": 499
  },
  {
    "timeStamp": 1644962277,
    "uID": "20200306",
    "capacityLeft": 300
  },
  {
    "timeStamp": 1644962279,
    "uID": "12345678",
    "capacityLeft": 753
  },
  {
    "timeStamp": 1644962281,
    "uID": "12345678",
    "capacityLeft": 752
  },
  {
    "timeStamp": 1644962283,
    "uID": "12345678",
    "capacityLeft": 751
  }
]

现在根据JSON,我需要 for each uID找到30个文档,并用时间戳对它们进行排序,这样当我查询我提到的所有设备时,我会得到提到的uID的最后30个文档,根据它们的数组索引对它们进行分组,然后将剩下的所有容量相加.

推荐答案

在我看来是这样的:

db.collection.aggregate([
{
 $match: {
  uID: {
    $in: [
      "20200308",
      "20200306"
    ]
  }
 }
},
{
 $sort: {
  uID: 1,
  "timeStamp": -1
 }
},
{
 $group: {
  _id: "$uID",
  ts: {
    $push: "$$ROOT"
  }
 }
},
{
 $project: {
  ts: {
    $slice: [
      "$ts",
      30
    ]
  }
 }
},
{
  $unwind: "$ts"
},
{
 $group: {
  _id: "$_id",
  sumcapLast30: {
    $sum: "$ts.capacityLeft"
  }
 }
}
])

解释:

  1. 匹配所有需要的uID
  2. 按uID排序,按时间戳描述
  3. 按uID分组
  4. 拼接并只保留ts数组的前30个元素.
  5. 展开ts数组
  6. 对每个uID的前30个元素进行分组和求和

playground

Node.js相关问答推荐

如何更改ejs中的镜像src,以防从OMDB API获取的某些镜像具有src=N/A

NPM:无法导入本码模块

如何从shell脚本中计算ecmascript模块?

如何使用多个参数完成

无法生成仅具有生产依赖项的 node 类型脚本项目

TS 后端开发:prismagenerate找不到已安装的@tsed/prisma包

使用 playwright 获取页面中同一 url 的所有响应

表达 js 错误处理程序在第一个之后被忽略

Typescript 正则表达式:过滤器返回空

我如何在 Raku 的供应中注册不同的事件?

错误 node :错误:绑定消息提供 16 个参数,但准备语句需要 15 个

等待不在 Express.js 中处理 res.app.render

Zod 模式中的self 数组

WSL2 上需要脚本运行的 NPM 包的权限被拒绝

postman 发送请求……永远

在安装 tensorflow 时遇到问题

构建 vue cli 后如何运行生产站点

从 CoffeeScript 中的数组中删除一个值

如何让should.be.false语法通过 jslint?

续集findbyid不是一个函数,但显然findAll是