HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Customer MapReduce implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationmapreducecustomer

Problem

I would love a second opinion / another pair of eyes on this.

```
db.customers.mapReduce(
function() {
Array.prototype.getUnique = function() {
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; ++i) {
if (u.hasOwnProperty(this[i])) {
continue;
}
a.push(this[i]);
u[this[i]] = 1;
}
return a;
}
var customer = this;
this.tags.getUnique().forEach(function(tag) {
if (customer.status) {
emit(customer.shop, {
"kind": "unique_customers_submitted",
"tag": tag.tag,
});
} else {
emit(customer.shop, {
"kind": "unique_customers_withheld",
"tag": tag.tag,
});
}
emit(customer.shop, {
"kind": "unique_customers_total",
"tag": tag.tag,
});
})
this.tags.forEach(function(tag) {
if (customer.status) {
emit(customer.shop, {
"kind": "total_customers_submitted",
"tag": tag.tag,
});
} else {
emit(customer.shop, {
"kind": "total_customers_withheld",
"tag": tag.tag,
});
}
emit(customer.shop, {
"kind": "total_customers",
"tag": tag.tag,
});
});
},
function(key, sets) {
var forms = {};
sets.forEach(function(set) {
if (typeof forms[set.tag] == "undefined") forms[set.tag] = {};
if (typeof forms[set.tag][set.kind] == "undefined") forms[set.tag][set.kind] = 0;
forms[set.tag][set.kind] += 1;
});
return forms;
}, {
out: "form_numbers",
},
functi

Solution

I'm not familiar with MR best practices, but here are some JS-specific comments.

Key Points

-
DRY - that emit code is repeated all over the place and has only slight changes - parameterize what varies and put it all in a function

-
You are repeating your loops - either do everything in one loop for better performance (and keep in mind that for is faster than forEach, or go fully functional (see next)

-
You are essentially doing a filter within your loop - use filter to remove the if logic from within the loop (or see previous). If you want to go even more functional, maybe you should use underscorejs or lo-dash, which both have a unique function already.

-
Never change the prototype of a builtin unless you have already checked if the method exists (like a polyfill) and/or you have a really, really good reason to do so. Mostly, just don't.

-
Declare functions so that they are not re-created (unless necessary)

-
You should probably close your db connection ASAP

-
Oh, and name your inline functions to provide better documentation

A simple refactoring hosted as a gist for easy forking

function getUnique() {
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
    return a;
};
function emitHelper(kind, shop, tag) {
    emit(shop, {
        "kind": kind,
        "tag": tag,
    });
};
db.customers.mapReduce(
    function mapCustomerToShopWithKindAndTag() {
        var customer = this;
        var kind;
        getUnique(this.tags).forEach(function(tag) {
            kind = customer.status ? "unique_customers_submitted" : "unique_customers_withheld";
            emitHelper(kind, customer.shop, tag.tag);
            emitHelper("unique_customers_total", customer.shop, tag.tag);
        });
        this.tags.forEach(function(tag) {
            kind = customer.status ? "total_customers_submitted" : "total_customers_withheld";
            emitHelper(kind, customer.shop, tag.tag);
            emitHelper("total_customers_total", customer.shop, tag.tag);
        });
    },
    function reduceToCountOfKindsPerTag(key, sets) {
        var forms = {};
        sets.forEach(function(set) {
            if (typeof forms[set.tag] == "undefined") forms[set.tag] = {};
            if (typeof forms[set.tag][set.kind] == "undefined") forms[set.tag][set.kind] = 0;
            forms[set.tag][set.kind] += 1;
        });
        return forms;
    }, {
        out: "form_numbers",
    },
    function(err, results) {
        console.log(err);
        //console.log(results);
        results.find().toArray(function(err, numbers) {
            db.server.close(); // Maybe wrap in a try/catch too
            console.log(err);
            console.log(JSON.stringify(numbers));
        });
    }
);

Code Snippets

function getUnique() {
    var u = {}, a = [];
    for (var i = 0, l = this.length; i < l; ++i) {
        if (u.hasOwnProperty(this[i])) {
            continue;
        }
        a.push(this[i]);
        u[this[i]] = 1;
    }
    return a;
};
function emitHelper(kind, shop, tag) {
    emit(shop, {
        "kind": kind,
        "tag": tag,
    });
};
db.customers.mapReduce(
    function mapCustomerToShopWithKindAndTag() {
        var customer = this;
        var kind;
        getUnique(this.tags).forEach(function(tag) {
            kind = customer.status ? "unique_customers_submitted" : "unique_customers_withheld";
            emitHelper(kind, customer.shop, tag.tag);
            emitHelper("unique_customers_total", customer.shop, tag.tag);
        });
        this.tags.forEach(function(tag) {
            kind = customer.status ? "total_customers_submitted" : "total_customers_withheld";
            emitHelper(kind, customer.shop, tag.tag);
            emitHelper("total_customers_total", customer.shop, tag.tag);
        });
    },
    function reduceToCountOfKindsPerTag(key, sets) {
        var forms = {};
        sets.forEach(function(set) {
            if (typeof forms[set.tag] == "undefined") forms[set.tag] = {};
            if (typeof forms[set.tag][set.kind] == "undefined") forms[set.tag][set.kind] = 0;
            forms[set.tag][set.kind] += 1;
        });
        return forms;
    }, {
        out: "form_numbers",
    },
    function(err, results) {
        console.log(err);
        //console.log(results);
        results.find().toArray(function(err, numbers) {
            db.server.close(); // Maybe wrap in a try/catch too
            console.log(err);
            console.log(JSON.stringify(numbers));
        });
    }
);

Context

StackExchange Code Review Q#42740, answer score: 6

Revisions (0)

No revisions yet.