首页 > 解决方案 > 聚合查询以在 mongodb 中的单个查询中获取所有不同的条件

问题描述

我的 mongodb 集合中的一个文档如下:

{
  "transaction_id": "e10cc8d64204394cd35329a88dc4ab8f",
  "timestamp": "2021-05-11 17:47:50",
  "client_id": "chae@aklas.kr",
  "ip": "172.69.34.31",
  "level": "OK",
  "request": {
    "method": "POST",
    "status_code": 200,
    "status_name": "Ok",
    "url": "/ocr/driver"
  },
  "bytes": 297,
  "message": "Status authenticated successfully"
},
{
  "transaction_id": "e10cc8d64204394cd35329a88dc4ab8f",
  "timestamp": "2021-05-11 17:47:50",
  "client_id": "chae@kkk.kr",
  "ip": "172.69.34.31",
  "level": "OK",
  "request": {
    "method": "POST",
    "status_code": 200,
    "status_name": "Ok",
    "url": "/status/driver"
  },
  "bytes": 297,
  "message": "Status authenticated successfully"
}......

我可以使用以下查询按时间戳(每天)获取每个 request.url 的总数。

db.getCollection('collection').aggregate([ 
    {
       $match: { 
            client_id: { $regex : '^chae@'}, 
           'request.url': { $regex : '^\/ocr'}}
    },
    { '$group' :
        {
            '_id': { $substr: [ "$timestamp", 0, 10 ] },
            count: { $sum: 1 }
        }
    },
    {
        '$sort':
            { 'count': -1}
     }
])

然后我得到 request.url 的结果,其中包含 /^ocr/

_id        |  count
2021-10-01 |  10
2021-09-30 |  15
2021-09-29 |  11
....

好像没问题。但是,如果我想获得不同的 request.url,我必须发送另一个查询。我可以通过一个查询一次获得所有不同 request.url 的结果吗?

我想要的结果是这样的。

_id        |  count(ocr) | count(status) | count(something else)
2021-10-01 |  10         | 20            | 56 
2021-09-30 |  15         | 26            | 28 
2021-09-29 |  11         | 87            | 466 

我什至不知道在mongodb中是否有可能?请给我提意见。谢谢。

标签: sqlmongodb

解决方案


询问

  • group 也接受表达式,所以我们可以计算 group 值
  • 这里我们有 2 个组键
  • 他们的电子邮件以 chae 开头,url 以 /ocr 开头的那些
  • 那些他们的电子邮件以 chae 开头,url 以 /status 开头的人
  • 我们分别总结这些
  • 如果您添加更多案例,$switch您可以为许多不同的搜索执行此操作
  • 如果您在编写查询时不知道这些情况,则需要{"$switch" ...}动态构建它,您可以使用循环来完成,它很容易做到,循环变量并创建它
  • 如果您在这些字段上有索引,则可以$match在顶部添加一个,例如仅允许
    (or (chae and /ocr) (chae and /status) ...)

还有一个$facet解决方案(方面 = 每个字段 1 个聚合)

  • 如果在 $match , $facet 或 $group 上使用 index 类似的性能(你做正则表达式匹配所以测试索引使用),但 $facet 更简单的查询
  • 如果没有索引,$facet每个字段将进行 1 次集合扫描,所以$group我认为

测试代码在这里

aggregate(
[{"$group": 
   {"_id": 
     {"reg": 
       {"$switch": 
         {"branches": 
           [{"case": 
              {"$and": 
                [{"$regexMatch": {"input": "$client_id", "regex": "^chae@"}},
                 {"$regexMatch": {"input": "$request.url", "regex": "^/ocr"}}]},
                "then": "chae-ocr"},
           {"case": 
             {"$and": 
               [{"$regexMatch": {"input": "$client_id", "regex": "^chae@"}},
                {"$regexMatch": 
                  {"input": "$request.url", "regex": "^/status"}}]},
                "then": "chae-status"}],
            "default": "other"}},
        "time": {"$substrCP": ["$timestamp", 0, 10]}},
      "count": {"$sum": 1}}},
  {"$project": {"_id": "$_id.time", "count": 1, "searched": "$_id.reg"}}])

推荐阅读