Как сохранить только определенное подмножество коллекции - PullRequest
1 голос
/ 07 октября 2011

Я хотел бы сохранить только определенное подмножество коллекции.Я не нахожу никакой соответствующей информации об этом.Это сложно объяснить, поэтому я привел пример:

Допустим, у меня есть эта коллекция:

db.mycollection.save({ "category" : 1201, "score" : 0.5});
db.mycollection.save({ "category" : 1201, "score" : 0.4});
db.mycollection.save({ "category" : 1201, "score" : 0.3});
db.mycollection.save({ "category" : 1201, "score" : 0.5});
db.mycollection.save({ "category" : 1201, "score" : 0.1});

db.mycollection.save({ "category" : 1202, "score" : 0.5});
db.mycollection.save({ "category" : 1202, "score" : 0.6});
db.mycollection.save({ "category" : 1202, "score" : 0.1});
db.mycollection.save({ "category" : 1202, "score" : 0.3});
db.mycollection.save({ "category" : 1202, "score" : 0.1});
db.mycollection.save({ "category" : 1202, "score" : 0.4});
db.mycollection.save({ "category" : 1202, "score" : 0.3});

db.mycollection.save({ "category" : 1203, "score" : 0.8});
db.mycollection.save({ "category" : 1203, "score" : 0.4});
db.mycollection.save({ "category" : 1203, "score" : 0.7});
db.mycollection.save({ "category" : 1203, "score" : 0.3});

db.mycollection.save({ "category" : 1204, "score" : 0.2});
db.mycollection.save({ "category" : 1204, "score" : 0.8});
db.mycollection.save({ "category" : 1204, "score" : 0.7});
db.mycollection.save({ "category" : 1204, "score" : 0.9});

Моя цель - получить лучшие 3 строки во всех категориях (относительно оценки),В этом примере я пытаюсь получить такой результат:

{ "category" : 1201, "score" : 0.5 }
{ "category" : 1201, "score" : 0.5 }
{ "category" : 1201, "score" : 0.4 }
{ "category" : 1202, "score" : 0.6 }
{ "category" : 1202, "score" : 0.5 }
{ "category" : 1202, "score" : 0.4 }
{ "category" : 1203, "score" : 0.8 }
{ "category" : 1203, "score" : 0.7 }
{ "category" : 1203, "score" : 0.4 }
{ "category" : 1204, "score" : 0.9 }
{ "category" : 1204, "score" : 0.8 }
{ "category" : 1204, "score" : 0.7 }

Но я действительно не знаю, как это сделать.Я нашел обходной путь запуска функции уменьшения карты, но это действительно очень медленно.Вот что я сделал:

var map = function()
{
    emit(this.category, this.score);
}

var reduce = function(key, values)
{
    var total = [];
    values.forEach(function(value)
    {
        total.push(value);
    });
    total.sort();
    total.reverse();
    total = total.splice(0, 3);

    return {scores: total};
}

db.mycollection.mapReduce(map, reduce, { out : "myoutput" } );
db.myoutput.find();
db.myoutput.drop();

Результат:

{ "_id" : 1201, "value" : { "scores" : [ 0.5, 0.5, 0.4 ] } }
{ "_id" : 1202, "value" : { "scores" : [ 0.6, 0.5, 0.4 ] } }
{ "_id" : 1203, "value" : { "scores" : [ 0.8, 0.7, 0.4 ] } }
{ "_id" : 1204, "value" : { "scores" : [ 0.9, 0.8, 0.7 ] } }

Это не совсем то, что я хотел, но он справился с работой.

Мой вопрос: Это можно сделать без использования map-Reduce?(Или с хорошей производительностью?)

PS: Извините, мой плохой английский.Я не бегло.


РЕДАКТИРОВАТЬ:

Я наконец пришел с этим решением:

var map = function()
{
   emit(this.category, this.score);
}

var reduce = function(key, values)
{
    var total = [];
    values.forEach(function(value)
    {
        if (value instanceof Array)
            total.concat(value);
        else if (value instanceof Object)
        {
             if (value.scores instanceof Array)
                total.concat(value.scores);
             else
                total.push(value.scores);
        }
        else
            total.push(value);
    });
    total.sort(function (a,b) { return b - a} );
    total = total.splice(0, 3);

    return {scores: total};
}

1 Ответ

0 голосов
/ 08 октября 2011

Вы можете очень легко получить свой результат для данной категории

db.myCollection.find({category : 1204}).sort({score : -1}.limit(3)

это даст 3 лучших результата для данной категории

затем вы можете сделать цикл категорий, но для этого потребуется много запросов (по одному на категорию).

Решение для уменьшения карты - единственный способ сделать это, и у вас, похоже, есть рабочее решение. Если вы хотите улучшить свою производительность, поработайте над функцией уменьшения, особенно над следующей, не очень хорошей частью:

values.forEach(function(value)
{
    total.push(value);
});
total.sort();
total.reverse();
total = total.splice(0, 3);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...