字符串操作和聚合



我在MongoDB中有一个日志集合,它的结构如下:

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

其中"query"字段是请求的url中的查询参数。我想计算按查询参数"name"分组的计数总数。例如,对于此集合:

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

看起来我无法使用聚合框架来进行这种字符串操作。我可以通过映射减少来实现这一点,但是映射减少操作可以成为聚合管道的一部分吗?

聚合框架没有解析字符串内容并将其分解为此操作所需的键/值对所需的字符串操作运算符。当前唯一可用的字符串操作是$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更快地处理这一问题,因此这将是一个更好的持续选项。

相关内容

  • 没有找到相关文章

最新更新