Для получения значений дочерних элементов используйте Mongo Map/Reduce.
У меня есть коллекция монго, я хочу получить общее значение 'number_of_ad_clicks' по заданному названию места, отметке времени и идентификатору варианта. Потому что у нас есть большие данные, так что было бы лучше использовать карту / уменьшить. Могут ли парни дать мне какое-нибудь предложение?
Вот моя коллекция в формате JSON
{ "_id" : ObjectId( "4e3c280ecacbd1333b00f5ff" ),
"timestamp" : "20110805",
"variants" : { "94" : { "number_of_ad_clicks" : 41,
"number_of_search_keywords" : 9,
"total_duration" : 0,
"os" : { "os_2" : 2,
"os_1" : 1,
"os_0" : 0 },
"countries" : { "ge" : 6,
"ca" : 1,
"fr" : 8,
"uk" : 4,
"us" : 6 },
"screen_resolutions" : { "(320, 240)" : 1,
"(640, 480)" : 5,
"(1024, 960)" : 5,
"(1280, 768)" : 5 },
"widgets" : { "widget_1" : 1,
"widget_0" : 0 },
"languages" : { "ua_uk" : 8,
"ca_en" : 2,
"ca_fr" : 2,
"us_en" : 5 },
"search_keywords" : { "search_keyword_8" : 8,
"search_keyword_5" : 5,
"search_keyword_4" : 4,
"search_keyword_7" : 7,
"search_keyword_6" : 6,
"search_keyword_1" : 1,
"search_keyword_3" : 3,
"search_keyword_2" : 2 },
"number_of_pageviews" : 18,
"browsers" : { "browser_4" : 4,
"browser_0" : 0,
"browser_1" : 1,
"browser_2" : 2,
"browser_3" : 3 },
"keywords" : { "keyword_5" : 5,
"keyword_4" : 4,
"keyword_1" : 1,
"keyword_0" : 0,
"keyword_3" : 3,
"keyword_2" : 2 },
"number_of_keyword_clicks" : 83,
"number_of_visits" : 96 } },
"site_name" : "fonter.com",
"number_of_variants" : 1 }
Вот моя попытка. но не удалось. Он моя попытка.
m = function() {
emit(this.query, {variants: this.variants});
}
r = function(key , vals) {
var clicks = 0 ;
for(var i = 0; i < vals.length(); i++){
clicks = vals[i]['number_of_ad_clicks'];
}
return clicks;
}
res = db.variant_daily_collection.mapReduce(m, r, {out : "myoutput", "query":{"site_name": 'fonter.com', 'timestamp': '20110805'}})
db.myoutput.find()
Может ли кто-нибудь предложить?
Большое спасибо, я пробую решение, но ничего не возвращаю. Я призываю mapreduce в следующем, что-то не так?
res = db.variant_daily_collection.mapReduce(map, reduce, {out : "myoutput", "query":{"site_name": 'facee.com', 'timestamp': '20110809', 'variant_id': '305'}})
db.myoutput.find()
1 ответ
emit
функция испускает как key
и value
,
Если вы привыкли к SQL, подумайте key
как твой GROUP BY
а также value
как твой SUM(), AVG(), etc.
,
В вашем случае вы хотите "группировать по": site_name, timestamp и идентификатор варианта. Похоже, у вас может быть более одного варианта, поэтому вам нужно будет перебрать варианты, например:
map = function() {
for(var i in variants){
var key = {};
key.timestamp = this.timestamp;
key.site_name = this.site_name;
key.variant_id = i; // that's the "94" string.
var value = {};
value.clicks = this.variants[i].number_of_ad_clicks;
emit(key, value);
}
}
Функция Reduce получит массив значений, каждое из которых выглядит следующим образом { clicks: 41 }
, Функция должна вернуть один объект, который выглядит одинаково.
Так что если вы получите values = [ {clicks:21}, {clicks:10}, {clicks:5} ]
вы должны вывести {clicks:36}
,
Итак, вы делаете что-то вроде этого:
reduce = function(key , vals) {
var returnValue = { clicks: 0 }; // initializing to zero
for(var i = 0; i < vals.length(); i++){
returnValue.clicks += vals[i].clicks;
}
return returnValue;
}
Обратите внимание, что value
от map
имеет ту же форму, что и возврат из reduce
,