我有一个集合,每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相关问答推荐

try 使用Express和连接池将数据插入MySQL数据库时出现拒绝访问错误

如何发送比特币BTC使用发送加密使用WIF密钥在 node ,js

Nestjs swc 错误:找不到模块项目路径/src/app.module

错误:0308010C:try 通过 Github 推送部署到 firebase 托管时出现数字

如何删除mongodb中嵌套数组中所有出现的数组元素

NPM 错误:修复upstream 依赖冲突安装 NPM 包(云功能)

图像存储在后端文件夹中,但使用 multer 和 react.js 在前端找不到

fs.writefile 选项参数的可能值,尤其是只读文件的整数

为什么我在生产环境中 deproy Next.js 示例项目时 CSS 不起作用?

无服务器无法获取所有记录事件对象验证失败?

添加git信息到create-react-app

编写可维护的事件驱动代码

使用 Webpack 和 font-face 加载字体

为什么 Node 控制台不显示功能代码?

node 应用程序是否有任何独立的 gui 模块

Node.js, require.main === 模块

Bootstrap 中的 Grunt 依赖冲突

如何判断MongoDB本机nodejs驱动程序中是否存在集合?

当我try 向我的 S3 存储桶 (Node.js) 发送内容时,AWS 缺少凭证

'node' 未被识别为内部或外部命令