[javascript] передать переменную в функцию по значению

doublemother

В чём суть проблемы: хочу я сделать в монге некую функцию для map-reduce:
var myfun = function(someParam, x, kk, ...) {
     function mapFunction {
     var obj = this;
     obj.x *= x;
     emit(this._id, obj);
     }
     function reduceFunction(id, val) {
     return val[0];
     }
     return db[someParam].mapReduce(mapFunction, reduceFunction, {query:{k:kk}, out:{inline:1}}).results;
}

В результате у меня при вызове случается ошибка:
Wed Oct 26 17:02:12 uncaught exception: map reduce failed:{
"assertion" : "map invoke failed: JS Error: ReferenceError: x is not defined nofile_b:2",
"assertionCode" : 9014,
"errmsg" : "db assertion failure",
"ok" : 0
}

Насколько я понимаю, это всё из-за того, что при попадании в недра mapReduce mapFunction уже не знает ни о каком x. Можно ли как-то создать функцию mapFunction, чтобы x в ней было просто константой и не терялось?

okis

задай её хардкодом, там сигнатура жестко задана и структура (которая emit) не должна меняться

doublemother

задай её хардкодом, там сигнатура жестко задана и структура (которая emit) не должна меняться
Не понял. Как я её могу хардкодить, если мне её надо передавать параметром в вышестоящую функцию?

okis

надо смотреть в сторону apply
http://www.alistapart.com/articles/getoutbindingsituations/

doublemother

Прикольно, только непонятно, что делать с учётом того, что в качестве this у mapFunction уже выступает объект.

doublemother

Попробовал заэпплаить объект на finalize-функцию, которой не нужен this, по аналогии с примером по ссылке, как ни извращаюсь, в итоге всё равно где-то передаётся объект или функция, ссылающиеся на исходную переменную, и либо этот объект, либо сама переменная не определены.
Типа такого:

function createFinalizeFunction {
return function {
var theObj = {
'x': x
};
return (function(k, v) {
v.x *= this.x;
return v;
}).apply(theObj, arguments);
};
}

return db[someParam].mapReduce(
mapFunction,
reduceFunction,
{
query:{k:kk},
out:{inline:1},
finalize:createFinalizeFunction
}).results;
};

Пробовал вынести theObj уровнем выше — тоже не помогло.

Fragaria

Как минимум в PHP при вызове функции map/reduce ей можно передать параметры в виде

$params = array(
'mapreduce' => $collectionName,
'map' => $map,
'reduce' => $reduce,
'query' => $query,
'scope' => array('xxx' => 5, 'yyy' => 6)
);

Переменные xxx и yyy появятся в глобальной области видимости внутри map/reduce функций. Они по понятным причинам будут readOnly, но это тебе не помешает, я так понял.

Fragaria

Вообще на скользкую дорожку ты встал :) Мы с этой монгой уже почти год ебемся... Очень уж много у нее неприятных особенностей.

Fragaria

Из документации по монге:

db.runCommand(
 { mapreduce : <collection>,
   map : <mapfunction>,
   reduce : <reducefunction>
   [, query : <query filter object>]
   [, sort : <sorts the input objects using this key. Useful for optimization, like sorting by the emit key for fewer reduces>]
   [, limit : <number of objects to return from collection>]
   [, out : <see output options below>]
   [, keeptemp: <true|false>]
   [, finalize : <finalizefunction>]
   [, scope : <object where fields go into javascript global scope >]
   [, jsMode : true]
   [, verbose : true]
 }
);

scope - то, что тебе нужно.

doublemother

Переменные xxx и yyy появятся в глобальной области видимости внутри map/reduce функций. Они по понятным причинам будут readOnly, но это тебе не помешает, я так понял.
Это конечно интереснее, но есть несколько моментов:
1. Тогда уж переменные можно "захардкодить", подставив в $map
2. Мне кажется, что если передавать код каждый раз по сети, это будет сильно медленнее, чем если вызывать серверную процедуру (которая в db.system.js хранится передавая ей только параметры Я неправ?
3. На самом деле возвращается не mapReduce а
return db[coll].mapReduce(...).results.sort(sortFunction).slice(10);
Такой вызов, как я понимаю, уже из пхп не провернёшь.

Fragaria

Во втором моем сообщении - выдержка из мануала по монге. В качестве map или reduce можно передать как сам текст функции, так и название заранее сохраненной функции.

Fragaria

И кстати насчет медленнее. Map/reduce в монге и так настолько медленный, что разница в передаче функции по сети будет о-малое от времени выполнения. А учитывая, что один инстанс mongod может в каждый момент времени выполнять только один map/reduce, использовать этот механизм для реалтайм-запросов становится очень сложно.

doublemother

И кстати насчет медленнее. Map/reduce в монге и так настолько медленный, что разница в передаче функции по сети будет о-малое от времени выполнения. А учитывая, что один инстанс mongod может в каждый момент времени выполнять только один map/reduce, использовать этот механизм для реалтайм-запросов становится очень сложно.
Фак! Я, когда читал мануал, думал, что, когда они говорят про однопоточность mapReduce, они имеют в виду, что сам js не параллелится. Пидарасы! Тогда один хер проще через find делать и на сервере отсекать лишнее.

Fragaria

Чувак, с которым я общался на монго-конфе в Москве (Mathias Stearn, разработчик MongoDB Core Server сказал, что как минимум до 2.2 к лучшему ничего не изменится. К 2.2 они обещали прикрутить гугловский V8 вместо SpiderMonkey, он должен уметь многопоточность.

doublemother

Интересно, что им мешает создавать несколько инстансов SpiderMonkey.

okis

а как блокировки разрешаться будут? Думаю, они оставили это движку (если инстанс всего один).

ava3443

гугловский V8 вместо SpiderMonkey, он должен уметь многопоточность
походу они его не сумели приготовить
у нас несколько лет в продакшене работает SpiderMonkey, с десятками и сотнями потоков
Оставить комментарий
Имя или ник:
Комментарий: