开发者

Flexible JavaScript functions (for MongoDB)

I'm working on some Map / Reduce queries for MongoDB and am trying to do the following (in a nutshell).

m = function()
{
    this.convert = function(val)
    {
        return val+1;
    }

    emit(convert(this.age), this.doesWearGla开发者_开发问答sses);
}

r = function(k, v)
{
    count = 0;
    for(var i = 0; i < v.length; i++)
    {
        count += v[i];
    }
    return count;
}

if(tuned)
{
    m.convert = function(val)
    {
        return val;
    }
}

/**
* Continue to running the M/R query
*/

It should be noted that I'm writing this as a Node.js application, but I assume most of the same principals apply to any JavaScript.

The issue is I don't think I can change it without creating an object, ala mTmp = new m();, however I can't because emit() (and everything else) isn't defined.

I tried using m.prototype.convert = function, but this doesn't work. The value of m.toString() doesn't change.


I think that you’re trying to part of m (the map function) behave differently depending on whether tuned is set. Is that right?

Unfortunately, since both the map and reduce functions get passed to MongoDB as strings with just the bodies of the functions, they won’t have access to any outside code or data — so any properties you set on the function just won’t be there when it’s executed.

If I’m understanding you correctly, I think these are your three best options:

  1. Define a different version of m for each case.

  2. Assemble m as a string, plunking in the right chunk of code depending on the value of tuned.

  3. Make m decide how to behave based on a variable, like this:

    m = function()
    {
        var result;
        if (tuned) {
            result = this.age;
        } else {
            result = this.age + 1;
        }
        emit(convert(this.age), this.doesWearGlasses);
    }
    

    …and give the tuned variable a second life inside MongoDB when you call mapReduce:

    collection.mapReduce(m, r, { scope: { tuned: tuned } });
    

    (FWIW, if the difference is, in fact, this simple, you could write m like this instead:)

    m = function()
    {
        emit(convert(tuned ? this.age : this.age + 1), this.doesWearGlasses);
    }
    

…let me know if you mean something different.


Since you're calling the constructor after defining the prototype function, this.convert will overwrite the already-defined prototype function.

You could overwrite the entire m constructor:

m = function()
{
    this.convert = function(val)
    {
        return val+1;
    }
}

if(tuned) {
    m = (function(mOld) {
        return function()
        {
            mOld.apply(this, arguments);
            this.convert = function(val){ return val; }
        }
    })(m);
}

// Test code
function doStuff(obj) {
    alert(obj.toString());
}

var mObj = new m();
doStuff(mObj);

It should work, but I don't know what else it may affect in your actual script.

Note that it's using a self-invocation pattern, which creates a closure.

I've added test code that demonstrates that this works given the constraints in the OP.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜