Как получить к этому доступ._id в функции map в MongoDB MapReduce?

#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 печатает идентификаторы по желанию. Я понятия не имею, почему.

Вопросы:

  1. Как мне получить _id текущего объекта в функции map для использования в MapReduce? это._id или this[‘_id’] не работает.
  2. Почему именно m1 и m2 не эквивалентны?

Ответ №1:

Заставил его работать… Я допустил довольно простые ошибки JS:

  1. внутренняя функция forEach() в функции map, похоже, перезаписывает «этот» объект; это уже не основной документ (который имеет _id), а итерированный объект внутри цикла)…
  2. … или это было просто потому, что в 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...
...
}
  

вероятно, будет работать просто отлично.

Надеюсь, это кому-то поможет.