使用 $in 查询时如何获取 mongoDB 中每个唯一 id 的 n 个文档?

发布于 2025-01-18 16:28:58 字数 1743 浏览 0 评论 0原文

我有一个集合,可以为每个UID(这是主要键)存储每2秒钟的数据。现在,我想对每个UID查询最后30个文档,并根据其索引编号将其分组。在这种情况下如何进行?如果我申请$限制,则仅返回所有UID的30个文档。

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

以上查询将返回所有文档,如何将查询限制为每个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,我需要为每个UID找到30个文档,并使用时间戳对其进行排序,以便当我查询所有提到的设备时,我会为上述UID提供最后30个文档阵列索引,然后总和剩下的所有容量。

I have a collection which stores data every 2 seconds for every uID (which is the primary key). Now I want to query last 30 documents for each uID and group them together according to their index number. How to proceed in this case? If I apply $limit, this returns only 30 documents for all uIDs.

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

The above query will return me all the documents, how to limit query to 30 doc per uID? Also if query is successful, how to group all the array indexes of distinct documents so that I get the sum of values of a field which has 30 documents grouped together. Example:

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

JSON example:

[
  {
    "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
  }
]

Now according the the JSON, I need to find 30 docs for each uID and sort them with timeStamp so that when I query for all my mentioned devices I get a last 30 docs for the mentioned uIDs, group them by their array index and then sum all the capacity left.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

如果没有 2025-01-25 16:28:58

在我看来是这样的:

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. Group 并对每个 uID 的前 30 个元素求和

playground

It looks to me something like this:

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"
  }
 }
}
])

Explained:

  1. Match all needed uID
  2. Sort by uID and desc by timeStamp
  3. group by uID
  4. splice and leave only the first 30 elements from the ts array.
  5. unwind the ts array
  6. Group and sum the first 30 elements per uID

playground

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文