Dynamic map-reduce

#1

Hey,
I have a bucket in which all docs structures are identical and have the following format:
“dateTime”: 1445666400000,
“favorites”: 0,
“clicks”: 0,


“customerId”: 15,
“campaignId”: 5819651,
“campaignName”: “twitter_CO_AU_android_HL”,

most of my needs from this documents is to summarize on each of the fields (favorites, clicks, etc…)
now to my understanding summarizing is faster using the map-reduce than it is using N1QL (from my experience the difference is huge.)
the only problem is i want to query dynamically according to parts of the campaignName in range of customerId and dateTime.
for example one of my reduce function currently look like this:

function (doc, meta) {
var idx = (meta.id).indexOf(":");
var docType = (meta.id).substring(0,idx);
if(meta.type == ‘json’ && docType == ‘twitterCampaignsStatistics’ && doc.customerId && doc.campaignId && doc.dateTime){
if(doc.campaignName.indexOf(“CO_”) > -1){
emit([doc.customerId,doc.dateTime],doc.clicks);
}
}
}

Which brings me to two questions:

  1. is there a way i switch the : " if(doc.campaignName.indexOf(“CO_”) > -1)" in way i can sometimes query for “Android” and otheres for “Iphone” and so on… or do i need to build a view for every regex i need? (because i want the possibility to pass the regex dynamically in some way…)
  2. can i sum into different results the values of “favorites”, “clicks”, etc… in the same view?

Thanks.

#2

It’s often hard to grasp what can or can’t be done with mapreduce views. I usually imagine the results of a view as a sorted list (they are sorted by key). If you find a way to cut out a single continuous slice out of it that answers your request your are good.

From what you’ve posted it sounds like it’s possible. If you prefix all your results with the phone platform you want to query on. So your emit looks like:

var platform = doc.campaignName.split('_')[3];
emit([platform, doc.customerId, doc.dateTime], doc.clicks);

In regards to summing up multiple values, you could use a custom reduce. First change your map function to:

emit([platform, doc.customerId, doc.dateTime], [doc.clicks, doc.favorites]);

And your reduce will then be:

function(keys, values, rereduce) {
    // rereduce isn't a special case here
    var empty = values[0].map(function() {return 0;});
    var result = values.reduce(function(a, b) {
        var sum = [];
        for (var i = 0; i < a.length; i++) {
            sum[i] = a[i] + b[i];
        }
        return sum;
    }, empty);
    return result;
}