mongodb count количество различных значений для поля / ключа

105

Есть ли запрос для расчета количества различных значений, содержащихся в поле в БД.

fe У меня есть поле для страны, и есть 8 типов значений страны (Испания, Англия, Франция и т. д.)

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

Есть ли способ попроще, чем сгруппировать и посчитать?

Лиатц
источник
2
Вы смотрели фреймворк агрегирования ?
WiredPrairie
1
Или карту-уменьшить ?
WiredPrairie

Ответы:

199

В MongoDB есть distinctкоманда, которая возвращает массив различных значений для поля; вы можете проверить длину массива для подсчета.

Также есть db.collection.distinct()помощник оболочки :

> db.countries.distinct('country');
[ "Spain", "England", "France", "Australia" ]

> db.countries.distinct('country').length
4
Стенни
источник
47
это на самом деле не работает, если у вас слишком большое количество различных значений ... если вы смотрели на разные имена людей в мире или что-то в этом роде. у вас есть ответ, который масштабируется?
Underrun
3
1+ по длине. я изо всех сил пытался найти что-то подобное. Спасибо.
Адил Ахмад,
Я не знаю, почему они также не используют count ()
Мариан Клюспис,
1
@ MarianKlühspies - потому что это просто массив javascript, который использует свойство length для подсчета количества элементов.
UpTheCreek
Именно то, что я искал ... TY
Maulzey
114

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

db.articles.aggregate([
    {
        $match: {
            keywords: { $not: {$size: 0} }
        }
    },
    { $unwind: "$keywords" },
    {
        $group: {
            _id: {$toLower: '$keywords'},
            count: { $sum: 1 }
        }
    },
    {
        $match: {
            count: { $gte: 2 }
        }
    },
    { $sort : { count : -1} },
    { $limit : 100 }
]);

которые дают такой результат, как

{ "_id" : "inflammation", "count" : 765 }
{ "_id" : "obesity", "count" : 641 }
{ "_id" : "epidemiology", "count" : 617 }
{ "_id" : "cancer", "count" : 604 }
{ "_id" : "breast cancer", "count" : 596 }
{ "_id" : "apoptosis", "count" : 570 }
{ "_id" : "children", "count" : 487 }
{ "_id" : "depression", "count" : 474 }
{ "_id" : "hiv", "count" : 468 }
{ "_id" : "prognosis", "count" : 428 }
эксперт
источник
2
Авторизовался только чтобы + этот ответ. Спасибо! Кстати, если вы делаете это в уникальном поле, просто удалите строку размотки.
Richie Rich
@RichieRich, unwindнеобходим, потому что код группирует отдельные значения поля массива, которое соответствует принципу distinctработы.
Пол
@Paul Ричи сказал, что если группировка выполняется просто "обычным" полем (строка, целое число и т. Д.), Тогда вам не нужен шаг размотки. Не правда ли?
гайарад
@guyarad unwindнеобходим при работе с массивами.
Пол
+1 за ответ, именно то, над чем я работал, хотя у разных есть свои прелести, но это просто золото :) - в любом случае мне нужно больше узнать об агрегатах, чтобы достичь желаемого набора результатов для фильтрации данных
Талха
21

В MongoDb 3.4.4 и новее вы можете использовать $arrayToObjectоператор и $replaceRootконвейер для получения подсчетов.

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

db.users.aggregate([
    { "$group": {
        "_id": { "$toLower": "$role" },
        "count": { "$sum": 1 }
    } },
    { "$group": {
        "_id": null,
        "counts": {
            "$push": { "k": "$_id", "v": "$count" }
        }
    } },
    { "$replaceRoot": {
        "newRoot": { "$arrayToObject": "$counts" }
    } }    
])

Пример вывода

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}
Chridam
источник
Это не ответ на вопрос, но, тем не менее, он полезен. Интересно, как это работает по сравнению с .distinct().
Redsandro
9

Вы можете использовать расширения Mongo Shell . Это единый импорт .js, который вы можете добавить в свой $HOME/.mongorc.jsили программно, если вы тоже кодируете на Node.js / io.js.

Образец

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

> db.users.distinctAndCount('name', {name: /^a/i})

{
  "Abagail": 1,
  "Abbey": 3,
  "Abbie": 1,
  ...
}

Параметр поля может быть массивом полей

> db.users.distinctAndCount(['name','job'], {name: /^a/i})

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}
Evandrix
источник
как мне импортировать это в узел?
Salmaan P
require("./script.js"), я полагаю
evandrix 06
правильно, но мне не удалось получить функции внутри. Как мне их использовать. Они определены как db.protoptype.distinctAndCount
Salmaan P
В readme репозитория есть раздел с практическими рекомендациями (RTFM! 1 !! 1!). По сути, поместите .mongorc.jsфайл в свой домашний каталог. Готово.
Janis F
7

Чтобы найти разные в field_1коллекции, но нам WHEREтоже нужно какое-то условие, чем мы можем сделать следующим образом:

db.your_collection_name.distinct('field_1', {WHERE condition here and it should return a document})

Итак, найдите число, отличное namesот коллекции, где возраст> 25 будет примерно таким:

db.your_collection_name.distinct('names', {'age': {"$gt": 25}})

Надеюсь, поможет!

Вимал
источник