Выбор n элементов, принадлежащих пользователю, в MapReduce для CouchDB - PullRequest
1 голос
/ 17 февраля 2011

Пожалуйста, потерпите меня, я новичок во всем, что касается CouchDb.

БД выглядит так:

** item ** count ** user **
   A       20       bob
   B       30       bob
   C       10       bob
   D       15       john

Я хочу написать MapReduce, который выбирает все элементы, принадлежащие Бобу, и возвращает только отсортированные верхние 2. поэтому он должен вернуть [{item:"B",count:"30"},{item:"A",count:"20}]

Я не уверен, как это можно сделать? Похоже, я должен излучать (doc.item, doc.count), но как мне узнать, если пользователь владеет документом? Как запустить другой MapReduce для выбора верхних элементов?

Ответы [ 2 ]

2 голосов
/ 18 февраля 2011

Если вы введете user и count в ключе представления, вы можете использовать startkey=["bob",""] и endkey=["bob"] для выбора пользователя и descending=true и limit=2 для получения двух верхних элементов.

Я попробовал следующую функцию карты:

function(doc) {
  if(doc.user && doc.count && doc.item) {
    emit([doc.user, doc.count], doc);
  }
}

со строкой запроса ?startkey=["bob",""]&endkey=["bob"]&descending=true&limit=2 возвращает:

{"total_rows":4,"offset":1,"rows":[
{"id":"item_B_bob","key":["bob",30],"value":{"_id":"item_B_bob","_rev":"1-b23bd22fb719c7d59b045bce0932df8c","item":"B","count":30,"user":"bob"}},
{"id":"item_A_bob","key":["bob",20],"value":{"_id":"item_A_bob","_rev":"2-515bca46eab383cfeaaa2a101d180291","item":"A","count":20,"user":"bob"}}
]}

Обратите внимание:

2 голосов
/ 17 февраля 2011

Одним из решений было бы написать ваше представление для использования сложного ключа, такого как:

function (doc) {
    emit([doc.user, doc.count], doc.item);
}

Если вы добавите descending=true в строку запроса, это даст вам такой результат просмотра, как:

{"total_rows":4,"offset":0,"rows":[
    {"id":"53f359b7cd360da296dd9aab3d0029bd","key":["john",15],"value":"D"},
    {"id":"53f359b7cd360da296dd9aab3d001a0e","key":["bob",30],"value":"B"},
    {"id":"53f359b7cd360da296dd9aab3d000fec","key":["bob",20],"value":"A"},
    {"id":"53f359b7cd360da296dd9aab3d002668","key":["bob",10],"value":"C"}
]}

Это уже отсортировано по пользователю, затем посчитайте. (с типом элемента в качестве значения)

Тогда вы можете использовать _list функцию , чтобы сделать все остальное. Приведенный ниже код в основном перебирает представление и возвращает 2 лучших результата для каждого пользователя. Если вы укажете user=bob в строке запроса, вы получите результаты только для bob.

function (head, req) {
    // specify that we're sending JSON as our response
    provides('json', function () {
        var results = [],
            result, user, count, row;

        while (row = getRow()) {
            // if the user doesn't match the last iteration, reset our counter
            if (user != row.key[0]) {
                user = row.key[0];
                count = 0;
            }

            // we only need the top 2
            if (count++ >= 2) {
                continue;
            }

            // start building a result object
            result = {
                item: row.value,
                count: row.key[1]
            };

            // if we provide user=?
            if (req.query.user) {
                // check to see if it matches the current user
                if (req.query.user === user) {
                    // if so, add it to the results
                    results.push(result);
                }
            // by default, we'll return the top 2 for every user
            } else {
                // add the user key to the result object
                result.user = row.key[0];
                // and add it to the result set
                results.push(result);
            }
        }

        // send outside the loop, since it needs to be sent as valid JSON
        send(JSON.stringify(results));
    });
}
...