2
votes

My map function returns key-value pairs where key is the name of a field and the value is an object {type: <field type>, count : 1}. For example suppose I have these documents:

{ 
    "_id" : ObjectId("57611ad6bcc0d7e01be886c8"), 
    "index" : NumberInt(0)
}
{
    "_id" : ObjectId("57611ad6bcc0d7e01be886c9"), 
    "index" : NumberInt(7)
}
{
    "_id" : ObjectId("57611ad6bcc0d7e01be886c7"), 
    "index" : NumberInt(9)
}

I have to retrieve the name of each field, its type and the number of occurrences of the field in my collection.

My map function works and I get:

"_id", [{type:"ObjectId", count:1},{type:"ObjectId", count:1},{type:"ObjectId", count:1}] 
"index",[{type:"number", count:1},{type:"number", count:1},{type:"number", count:1}]

I want to delete duplicates from type.

I have the following reduce function:

function (key, stuff) {

reduceVal = {type:"", count:0};
var array = [];

for(var idx =0; idx < stuff.length; idx++) {

  reduceVal.count += stuff[idx].count;

  if(array.indexOf(stuff[idx].type) > -1) {
  array.push(stuff[idx].type);
  }
}

reduceVal.type = array.toString();

The if clause does not work. My target is to add an element to my array just if it is not a duplicate. Expected output:

"_id", {type:"ObjectId", count:3}
"index", {type:"number", count:3}

How can I fix?

2
Is it possible to edit your question to include a sample of documents, perhaps one or two, and the expected output from the aggregation operation? There's a strong chance that what you are trying to achieve can be done with much better performance with the aggregation framework rather than MapReduce, so it wold be great to show this intent through a sample and the desired output as a document. - chridam
You need to tell us what you are trying to achieve and show us your expected output. - styvane
Ok, I have added details. - DistribuzioneGaussiana

2 Answers

0
votes

The reduce function works. The if statement was wrong: I have to add an element to my array when if(array.indexOf(stuff[idx].type) === -1).

-1
votes

It looks like you just jumbled up your reduce function. As far as I can interpret this, you assume that the reducer is called once globally. This is not the case. Instead, it is called per key, i.e. the input to the reducer is somthing like:

First call:

key = "ObjectId", val = [{type:"ObjectId", count:1},{type:"ObjectId", count:1},{type:"ObjectId", count:1}]

Second call:

key = "number", val = [{type:"number", count:1},...]

Therefore, you need to sum up, knowing that the key is already set (this code is not tested and will have its shortcomings):

function(key, vals) {
    var sum = 0;
    for(var i = 0; i < vals.length; i++) {
        sum += vals[i].count;
    }
    return { "type" : key, "count" : sum };
}