mongodb cuenta número de valores distintos por campo / clave

104

¿Existe una consulta para calcular cuántos valores distintos contiene un campo en la base de datos?

fe tengo un campo para país y hay 8 tipos de valores de país (españa, inglaterra, francia, etc ...)

Si alguien agrega más documentos con un nuevo país, me gustaría que la consulta devuelva 9.

¿Hay una manera más fácil que agrupar y contar?

Liatz
fuente
2
¿Ha mirado el marco de agregación ?
WiredPrairie
1
¿O reducir el mapa ?
WiredPrairie

Respuestas:

198

MongoDB tiene un distinctcomando que devuelve una matriz de valores distintos para un campo; puede comprobar la longitud de la matriz para un recuento.

También hay un db.collection.distinct()asistente de shell :

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

> db.countries.distinct('country').length
4
Stennie
fuente
47
esto realmente no funciona si su número de valores distintos es demasiado alto ... si estuviera buscando nombres distintos de personas en el mundo o algo así. tienes una respuesta que escala?
insuficiencia de datos en
3
1+ para la longitud. Estaba luchando por encontrar algo así. Gracias.
Adeel Ahmad
No sé por qué no usan count () allí también
Marian Klühspies
1
@ MarianKlühspies - porque es solo una matriz javascript, que usa la propiedad length para contar el número de elementos.
UpTheCreek
Justo lo que estaba buscando ... TY
Maulzey
113

A continuación se muestra un ejemplo del uso de la API de agregación. Para complicar el caso, estamos agrupando palabras que no distinguen entre mayúsculas y minúsculas de la propiedad de matriz del documento.

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 }
]);

que dan resultado como

{ "_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 }
experto
fuente
2
Inició sesión solo para + esta respuesta. ¡Gracias! por cierto, si lo hace en un campo único, simplemente elimine la línea de desenrollado.
Richie Rich
@RichieRich, unwindes necesario porque el código agrupa valores individuales de un campo de matriz que coincide con cómo distinctfunciona.
Paul
@Paul lo que Richie dijo es que si la agrupación se realiza solo en un campo "normal" (cadena, int, etc.), entonces no necesita el paso de desenrollado. ¿No es correcto?
Guyarad
@guyarad unwindes necesario cuando se trabaja con matrices.
Paul
+1 para la respuesta, exactamente en lo que estaba trabajando, por diferente que sea tiene sus propios encantos, pero esto es solo oro :) - de todos modos, tengo que leer más sobre los agregados para lograr el conjunto de resultados deseado para filtrar datos
Talha
21

Con MongoDb 3.4.4 y versiones posteriores, puede aprovechar el uso del $arrayToObjectoperador y una $replaceRootcanalización para obtener los recuentos.

Por ejemplo, suponga que tiene una colección de usuarios con diferentes roles y le gustaría calcular los distintos recuentos de roles. Debería ejecutar la siguiente canalización agregada:

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

Salida de ejemplo

{
    "user" : 67,
    "superuser" : 5,
    "admin" : 4,
    "moderator" : 12
}
chridam
fuente
Esta no es la respuesta a la pregunta, pero de todos modos es útil. Me pregunto cómo funciona esto en comparación con .distinct().
Redsandro
9

Puede aprovechar las extensiones de Mongo Shell . Es una sola importación .js que puede agregar a su $HOME/.mongorc.js, o programáticamente, si también está codificando en Node.js / io.js.

Muestra

Para cada valor distinto del campo, se cuentan las ocurrencias en los documentos, opcionalmente filtrados por consulta.

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

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

El parámetro de campo podría ser una matriz de campos.

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

{
  "Austin,Educator" : 1,
  "Aurelia,Educator" : 1,
  "Augustine,Carpenter" : 1,
  ...
}
Evandrix
fuente
¿Cómo importaría esto en el nodo?
Salmaan P
require("./script.js"), supongo
evandrix
correcto, pero no pude obtener las funciones adentro. ¿Cómo los uso? Se definen como db.protoptype.distinctAndCount
Salmaan P
Hay una sección de procedimientos en el .mongorc.jsarchivo Léame del repositorio (RTFM! 1 !! 1!) Básicamente, coloque el archivo en su directorio de inicio. Hecho.
Janis F
6

Para encontrar distintos en field_1en la colección, pero también queremos alguna WHEREcondición de la que podemos hacer como sigue:

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

Entonces, encuentre un número distinto namesde una colección donde la edad> 25 será como:

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

¡Espero eso ayude!

Vimal
fuente