Как использовать Distinct, Sort, Limit с mongodb

У меня есть структура документа {'text': 'here is text', 'count' : 13, 'somefield': value}

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

distinct возвращает уникальное значение в списке.

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


person Kracekumar    schedule 03.04.2012    source источник


Ответы (1)


Не могли бы вы уточнить, что именно вы хотели бы сделать? Вы хотите вернуть документы с уникальными значениями «текста» с наибольшим значением «количества»?

Например, учитывая коллекцию:

> db.text.find({}, {_id:0})
{ "text" : "here is text", "count" : 13, "somefield" : "value" }
{ "text" : "here is text", "count" : 12, "somefield" : "value" }
{ "text" : "here is text", "count" : 10, "somefield" : "value" }
{ "text" : "other text", "count" : 4, "somefield" : "value" }
{ "text" : "other text", "count" : 3, "somefield" : "value" }
{ "text" : "other text", "count" : 2, "somefield" : "value" }
>
(I have omitted _id values for brevity)

Вы хотите вернуть только те документы, которые содержат уникальный текст с наибольшим значением «количества»?

{ "text" : "here is text", "count" : 13, "somefield" : "value" }

а также

{ "text" : "other text", "count" : 4, "somefield" : "value" }

Один из способов сделать это — использовать функции $group и $max в новой структуре агрегации. Документацию по $group можно найти здесь: http://docs.mongodb.org/manual/aggregation/

> db.text.aggregate({$group : {_id:"$text", "maxCount":{$max:"$count"}}})
{
    "result" : [
        {
            "_id" : "other text",
            "maxCount" : 4
        },
        {
            "_id" : "here is text",
            "maxCount" : 13
        }
    ],
    "ok" : 1
}

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

В качестве альтернативы вы можете сначала запустить команду «различные», чтобы вернуть массив всех различных значений, а затем выполнить запрос для каждого значения с сортировкой и ограничением, чтобы вернуть документ с наибольшим значением «количество». Методы sort() и limit() объясняются в разделе «Методы курсора» документации «Расширенные запросы»: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries.-CursorMethods

> var values = db.runCommand({distinct:"text", key:"text"}).values
> values
[ "here is text", "other text" ]
> for(v in values){var c = db.text.find({"text":values[v]}).sort({count:-1}).limit(1); c.forEach(printjson);}
{
    "_id" : ObjectId("4f7b50b2df77a5e0fd4ccbf1"),
    "text" : "here is text",
    "count" : 13,
    "somefield" : "value"
}
{
    "_id" : ObjectId("4f7b50b2df77a5e0fd4ccbf4"),
    "text" : "other text",
    "count" : 4,
    "somefield" : "value"
}

Неясно, именно это вы пытаетесь сделать, но я надеюсь, что это по крайней мере даст вам некоторые идеи для начала. Если я неправильно понял, объясните, пожалуйста, более подробно, какую именно операцию вы хотели бы выполнить, и, надеюсь, я или другой член Сообщества смогу вам помочь. Спасибо.

person Marc    schedule 03.04.2012
comment
Вы хотите вернуть только те документы, которые содержат уникальный текст с наибольшим значением «количества»? да . Я попробовал агрегат, кажется, pymongo не поддерживает агрегат, я попробовал db.command, но это не удалось, я буду экспериментировать, второй метод кажется простым, меня беспокоит сложность и время прохождения туда и обратно, так как это выполняется через от нескольких тысяч до нескольких сотен тысяч документов (в настоящее время 10 тыс.). Спасибо за 2 ответа, получение уникальных записей займет постоянное время (увеличивается с увеличением количества документов), а сортировка по убыванию также займет m * n lg , m - уникальные записи. - person Kracekumar; 04.04.2012
comment
Команда агрегата может быть запущена в PyMongo следующим образом: res = db.command({aggregate:text, pipe:[{$group : {_id:$text, maxCount:{$max:$count}}}]}) Документация API PyMongo по командам находится здесь: api.mongodb.org/python/current/api/pymongo/ Похоже, что агрегат не нужен для вашего приложения, но все же полезно знать, как использовать агрегацию в PyMongo. для дальнейшего использования. - person Marc; 05.04.2012
comment
В качестве общего совета часто предпочтительнее добавить немного дополнительных накладных расходов на каждую вставку и добавить дополнительный ключ к каждому документу, который может быть запрошен, в отличие от выполнения больших вычислений (таких как MapReduce или Aggregation). команда) каждый раз, когда данные извлекаются. В качестве альтернативы можно рассмотреть возможность добавления ключа isMaxCountforText (или его эквивалента) в каждый документ. Каждый раз, когда документ добавляется или обновляется, ключ счетчика можно сверять с другими документами, содержащими тот же текст, и соответственно обновлять isMaxCountforText. - person Marc; 05.04.2012