我有一个庞大的MongoDB数据库,因为尝试计数文件使它崩溃,我需要为此创建一个函数:
查询是:
M_logs[from]
.find()
.select('referer')
.where('time')
.gt(lower_bound)
.lt(upper_bound);
哪个给我(简化的,真实的数据是> 1k文件):
[ { _id: 53db8f924a1cb7d34a0001e3, referer: '' },
{ _id: 53dbe3ef4a1cb7655b008f4d, referer: '' },
{ _id: 53dbe3ef4a1cb7655b008f4e, referer: '' },
{ _id: 53dbe3ef4a1cb7655b008f4f,
referer: 'http://www.url1.com'
{ _id: 53dbe3ef4a1cb7655b008f50,
referer: 'http://url1.com' },
{ _id: 53dbe3ef4a1cb7655b008f51,
referer: 'http://www.url1.com' }
{ _id: 53dbe3ef4a1cb7655b008f52,
referer: 'http://www.url1.com' },
{ _id: 53dbe3ef4a1cb7655b008f53,
referer: 'http://www.url1.com'
{ _id: 53ed5bc64a1cb7f78c00361e,
referer: 'http://url1.com' },
{ _id: 53ef80384a1cb7019c0000c5,
referer: 'http://url2'}
]
正如你所看到的,有些日志是有缺陷和空的,有些是带有前缀为www的网址,有些则没有。由于我需要显示每个网址给我们的访问者数量,因此我需要对其进行解析以仅获取' url1.com',' url2.com',并忽略空字段。并计算每次出现的时间。
代码是:
function referer_process(result, referer, index, j, callback) {
var ur,
host;
result.forEach(function (element) {
ur = url.parse(element.referer, false, false);
if (ur.host) {
if (ur.host.search('www.') === 0) {
host = ur.host.substring(4);
} else {
host = ur.host;
}
if (!index[host]) {
console.log('.' + host + '. ' + host.length);
index[host] = j;
j = j + 1;
referer[index[host]] = {name: host, y: 1};
} else {
referer[index[host]].y = referer[index[host]].y + 1;
}
}
});
callback(referer, index, j);
}
当我们看到结果时出现问题,如果result
前两行具有相同的引用(一旦解析),其中一行被分配给不同的计数,但其他一切都很顺利。
示例:
url1.com: 5
url1.com: 1
url2.com: 1
我不明白它是如何发生的,因为每个都是同步的,所以必须在第二次遇到url1时创建索引!
这怎么可能发生?我在哪里可以搜索解决方案?
答案 0 :(得分:0)
我建议你做的是在mongo shell中使用mapReduce代替这些问题。以下是您使用它的方式:
TIME_UPPER_BOUND = ...
TIME_LOWER_BOUND = ...
var map = function() {
var host = this.referer;
if (host && host.substring(0, 4) == 'http') {
host = host.substring(7);
}
if (host && host.substring(0, 3) == 'www') {
host = host.substring(4);
}
emit(host, 1);
};
var reduce = function(key, values) {
return Array.sum(values);
};
var option = {
query: {time: {$gt: TIME_LOWER_BOUND, $lt: TIME_UPPER_BOUND}},
out: {inline: 1},
};
db.refers.mapReduce(map, reduce, option).results;
根据您在上面提供的数据,这将输出:
[
{
"_id" : "",
"value" : 3
},
{
"_id" : "url1.com",
"value" : 6
},
{
"_id" : "url2",
"value" : 1
}
]
很干净。请务必将refers
替换为您的收藏名称:db.<collection>.mapReduce
。您可以在此处找到有关mapReduce的更多信息:http://docs.mongodb.org/manual/core/map-reduce/