Попытка получить количество каждого слова в поле MongoDB — это задание для MapReduce?

#mongodb #node.js #mapreduce

#mongodb #node.js #mapreduce

Вопрос:

У меня есть коллекция с кучей основных сообщений в ней. Например:

 posts = { { id: 0, body: "foo bar baz", otherstuff: {...} },
          { id: 1, body: "baz bar oof", otherstuff: {...} },
          { id: 2, body: "baz foo oof", otherstuff: {...} }
        };
  

Я хотел бы выяснить, как перебирать каждый документ в коллекции и переносить количество каждого слова в текст каждой записи.

 post_word_frequency = { { foo: 2 },
                        { bar: 2 },
                        { baz: 3 },
                        { oof: 2 },
                      };
  

Я никогда не использовал MapReduce, и я все еще новичок в mongo, но я просматриваю документацию поhttp://cookbook.mongodb.org/patterns/unique_items_map_reduce /

 map = function() {
    words = this.body.split(' ');
    for (i in words) {
       emit({ words[i] }, {count: 1});   
    }
};

reduce = function(key, values) {
     var count = 0;
     values.forEach(function(v) {
          count  = v['count'];
     });
     return {count: count};
};

db.posts.mapReduce(map, reduce, {out: post_word_frequency});
  

В качестве дополнительной сложности я делаю это в node.js (с node-mongo-native, хотя я готов переключиться на выполнение запроса reduce, если есть более простой способ).

     var db = new Db('mydb', new Server('localhost', 27017, {}), {native_parser:false});
    db.open(function(err, db){
            db.collection('posts', function(err, col) {
                db.col.mapReduce(map, reduce, {out: post_word_frequency});
            });
    });
  

Пока у меня возникают трудности с тем, что этот узел сообщает мне ReferenceError: post_word_frequency is not defined (я пытался создать его в командной строке, но это все равно не помогло).

Итак, кто-нибудь делал mapreduce с node.js ? Это неправильное использование map reduce? может быть, другой способ сделать это? (возможно, просто зациклить и вставить в другую коллекцию?)

Спасибо за любые отзывы и советы! 🙂

ПРАВКА Ryanos ниже была правильной (спасибо!) Единственное, чего не хватает в моем решении на основе MongoDB, — это найти коллекцию и преобразовать ее в массив.

  db.open(function(err, db){
    db.collection('posts', function(err, col) {
            col.find({}).toArray(function(err, posts){    // this line creates the 'posts' array as needed by the MAPreduce functions.
                    var words= _.flatten(_.map(posts, function(val) {
  

Ответ №1:

Есть ошибка с {out: post_word_frequency} maybe you want {out: "post_word_frequency"} , но она должна работать без этой out переменной.

С помощью underscore это можно просто сделать.

 /*
  [{"word": "foo", "count": 1}, ...]
*/
var words = _.flatten(_.map(posts, function(val) {
    return _.map(val.body.split(" "), function(val) {
        return {"word": val, "count": 1};
    });
}));

/*
  {
    "foo": n, ...
  }
*/
var count = _.reduce(words, function(memo, val) {
    if (_.isNaN(  memo[val.word])) {
        memo[val.word] = 1;
    }
    return memo;
}, {});
  

Живой пример

_.reduce , _.map , _.isNaN , _.flatten

Комментарии:

1. это потрясающе! Спасибо. Я проверю ответ, когда вернусь домой с работы, и дам вам знать, если он сработает. Я никогда раньше не видел подчеркивания, это можно загрузить в node.js ?

2. @AlexC просто npm install underscore amp;amp; var _ = require("underscore");

3. отлично! в вашем примере это определенно работает — я все еще пытаюсь собрать все точки в бите mongo, но я уверен, что это скоро произойдет. Огромное спасибо! 🙂