【问题标题】:String manipulation and aggregation字符串操作和聚合
【发布时间】:2023-04-04 14:15:01
【问题描述】:

我在 MongoDB 中有一个日志集合,其结构如下所示:

{
  url : "http://example.com",
  query : "name=blah,;another_param=bleh",
  count : 5
}

其中“查询”字段是请求网址中的查询参数。 我想计算按查询参数“名称”分组的总数。例如,对于这个集合:

[{
 url : "http://example.com",
 query : "name=blah,;another_param=bleh",
 count : 3
},
{
 url : "http://example.com",
 query : "name=blah,;another_param=xyz",
 count : 4
},
{
 url : "http://example.com",
 query : "name=another_name,;another_param=bleh",
 count : 3
}]

我需要这个输出:

[{
  key : "blah",
  count : 7
 },
 {
  key : "another_name",
  count : 3
 }]

看起来我无法使用聚合框架进行此字符串操作。我可以通过 map-reduce 做到这一点,但是 map-reduce 操作可以成为聚合管道的一部分吗?

【问题讨论】:

    标签: javascript mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    聚合框架没有必要的字符串操作运算符来剖析字符串内容并将其分解为此操作所需的键/值对。当前唯一可用的字符串操作是$substr,除非您处理固定长度的数据,否则它不会有帮助。

    因此,目前唯一的服务器端方法是使用 mapReduce,因为您可以只使用可用的 JavaScript 函数来进行正确的操作。像这样的:

    对于映射器:

    function() {
         var obj = {};
         this.query.split(/,;/).forEach(function(item) { 
             var temp = item.split(/=/); 
             obj[temp[0]] = temp[1]; 
         });
    
         if (obj.hasOwnProperty('name')
             emit(obj.name,this.count);
    
    }
    

    还有减速器:

    function(key,values) {
       return Array.sum( values );
    }
    

    这是拆分“名称”参数并将它们用作聚合的“键”或“键”出现的一般计数所需的 JavaScript 函数的基本结构。

    因此聚合框架本身不能执行任何 JavaScript,因为它只是在数据上运行本机代码运算符。

    查看更改数据的存储方式是个好主意,以便在将文档插入 MongoDB 时将元素分解为“对象”表示而不是字符串。这允许不依赖 JavaScript 执行的原生查询表单来操作数据:

    [{
     "url": "http://example.com",
     "query": {
         "name": "blah",
         "another_param": "bleh"
     },
     "count": 3
    },
    {
     "url": "http://example.com",
     "query": {
         "name": "blah",
         "another_param": "xyz"
     },
     "count": 4
    },
    {
     "url": "http://example.com",
     "query": { 
         "name": "another_name",
         "another_param": "bleh"
     },
     "count": 3
    }]
    

    这使得$group 管道阶段变得非常简单,因为数据现在以可以本地处理的形式组织:

    { "$match": { "query.name": { "$exists": true } },
    { "$group": {
        "_id": "$query.name",
        "count": { "$sum": "$count" }
    }}
    

    所以现在使用 mapReduce,但最终考虑更改数据记录以从查询字符串中拆分“令牌”并将其表示为结构化数据,可选择将原始字符串保留在另一个字段中。

    聚合框架的处理速度比 mapReduce 快得多,因此这将是更好的持续选择。

    【讨论】:

    • 感谢尼尔的详细解释。
    • 嗨 Neil,你知道是否有一种方法可以通过传入参数来过滤 map 函数中使用的文档。例如,我只想对“url”为“example.com”的文档进行上述聚合。我目前只有 mapreduce 选项可用。
    • @NavinViswanath mapReduce 采用标准查询参数,因此您可以在那里指定您需要的内容。这是最好的做法,但如上所示,map 函数不需要发出任何东西,您可以根据逻辑中的条件发出,如图所示。
    • 谢谢。我看到了 mapReduce 的查询参数,这对我有用。但是我将如何在地图功能本身中做到这一点?有没有办法将参数传递给 map 函数?
    猜你喜欢
    • 1970-01-01
    • 2014-11-05
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2020-12-17
    • 2013-07-04
    • 2016-12-03
    • 2017-09-14
    相关资源
    最近更新 更多