#mongodb
#mongodb
Вопрос:
Я делаю MapReduce в Mongo для создания обратного индекса токенов для некоторых документов. У меня возникли проблемы с доступом к _id документа в функции map.
Пример документа:
{
"_id" : ObjectId("4ea42a2c6fe22bf01f000d2d"),
"attributes" : {
"name" : "JCDR 50W38C",
"upi-tokens" : [
"50w38c",
"jcdr"
]
},
"sku" : "143669259486830515"
}
(Поле ttributes[‘upi-tokens’] представляет собой список текстовых токенов, для которых я хочу создать обратный индекс.)
Функция Map (источник проблемы):
m = function () {
this.attributes['upi-tokens'].forEach(
function (token) { emit(token, {ids: [ this._id ]} ); }
); }
Уменьшить функцию:
r = function (key, values) {
var results = new Array;
for (v in values) {
results = results.concat(v.ids);
}
return {ids:results};
}
Вызов MapReduce:
db.offers.mapReduce(m, r, { out: "outcollection" } )
ПРОБЛЕМА Результирующая коллекция имеет нулевые значения везде, где я ожидал бы id вместо фактических строк ObjectId.
Возможная причина:
Я ожидал, что следующие 2 функции будут эквивалентны, но это не так.
m1 = function (d) { print(d['_id']); }
m2 = function () { print(this['_id']); }
Теперь я запускаю:
db.offers.find().forEach(m1)
db.offers.find().forEach(m2)
Разница в том, что m2 печатает неопределенные значения для каждого документа, в то время как m1 печатает идентификаторы по желанию. Я понятия не имею, почему.
Вопросы:
- Как мне получить _id текущего объекта в функции map для использования в MapReduce? это._id или this[‘_id’] не работает.
- Почему именно m1 и m2 не эквивалентны?
Ответ №1:
Заставил его работать… Я допустил довольно простые ошибки JS:
- внутренняя функция forEach() в функции map, похоже, перезаписывает «этот» объект; это уже не основной документ (который имеет _id), а итерированный объект внутри цикла)…
-
… или это было просто потому, что в JS for..in цикл возвращает только ключи, а не значения, т.е.
для (v в значениях) {
теперь требуется
values[v]
чтобы получить доступ к фактическому значению массива. Дух…
Способ, которым я обошел ошибку № 1, заключается в использовании for..in цикл вместо цикла …forEach() в функции map:
m = function () {
for (t in this.attributes['upi-tokens']) {
var token = this.attributes['upi-tokens'][t];
emit (token, { ids: [ this._id ] });
}
}
Таким образом, «это» относится к тому, что ему нужно.
Можно также сделать:
that = this;
this.attributes['upi-tokens'].forEach( function (d) {
...
that._id...
...
}
вероятно, будет работать просто отлично.
Надеюсь, это кому-то поможет.