【问题标题】:Aggregate query to get all different condition at single query in mongodb聚合查询以在 mongodb 中的单个查询中获取所有不同的条件
【发布时间】:2021-12-12 16:51:27
【问题描述】:

我的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中是否可以? 请建议我。 谢谢。

【问题讨论】:

    标签: sql mongodb


    【解决方案1】:

    查询

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

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

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

    Test code here

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

    【讨论】:

      【解决方案2】:

      您可以使用$facet 获得多个这样的结果:

      如果您使用任何编程语言,您可以轻松地为查询创建对象以不重复代码。

      db.collection.aggregate({
        "$facet": {
          "ocr": [
            // your query here
          ],
          "status": [
            // your query using $regex : '^\/status'
          ],
          "whatever":[
            // your query using $regex : '^\/whatever'
          ]
        }
      })
      

      例如here

      【讨论】:

      • 这似乎正是我想要的。我根据代码中的代码示例重写了代码。只是将 json 更改为数组。但 $facet 不适用于我的 php 代码。
      猜你喜欢
      • 2021-01-11
      • 2017-02-22
      • 2017-02-16
      • 2019-02-03
      • 1970-01-01
      • 1970-01-01
      • 2018-08-16
      • 1970-01-01
      • 2017-08-06
      相关资源
      最近更新 更多