2011-06-12 13 views
6

Tengo una colección MongoDB y necesito encontrar el valor máximo() de un determinado campo en todos los documentos. Este valor es la marca de tiempo y necesito encontrar el último documento encontrando la marca de tiempo más grande. Ordenarlo y obtener el primero se vuelve ineficiente realmente rápido. ¿Debo mantener un 'maxval' por separado y actualizarlo cada vez que un documento llega con un valor mayor para ese campo? ¿Alguna mejor sugerencia? Muchas gracias.Mongo no tiene una función max(), ¿cómo puedo solucionar esto?

Respuesta

3

Seguramente si será una gran colección y si siempre necesita mostrar la marca de tiempo máxima, puede necesitar crear una colección separada y almacenar datos estadísticos allí en lugar de pedir una gran colección cada vez.

statistic 
{ 
    _id = 1, 
    id_from_time_stamp_collection = 'xxx', 
    max_timestamp: value 
} 

Y cada vez que vienen nuevo documento solo actualizar recopilación de estadísticas con id = 1 (con la condición $ gt en la consulta, por lo que si la nueva marca de tiempo será mayor que max_timestamp continuación max_timestamp se actualizará, de lo contrario - no).

También es probable que pueda almacenar y actualizar otros datos estadísticos dentro de la recopilación de estadísticas.

+0

Andrew, sí, las colecciones crecerán a gran velocidad: imagine que son registros de registro (no exactamente la misma idea), y llegan a 10 millones de filas en un día más o menos. No es necesario que muestre max_ts solo utilícelo para buscar el último registro guardado de una clave determinada que tiene una serie de registros guardados según las visitas de los clientes al sitio. Entonces, algo en lo que has sugerido es en lo que estaba pensando. – Nitin

-3

Pruebe con db.collection.group

Por ejemplo, con esta colección:

> db.foo.find() 
{ "_id" : ObjectId("..."), "a" : 1 } 
{ "_id" : ObjectId("..."), "a" : 200 } 
{ "_id" : ObjectId("..."), "a" : 230 } 
{ "_id" : ObjectId("..."), "a" : -2230 } 
{ "_id" : ObjectId("..."), "a" : 5230 } 
{ "_id" : ObjectId("..."), "a" : 530 } 
{ "_id" : ObjectId("..."), "a" : 1530 } 

Usted puede utilizar group usando

> db.foo.group({ 
    initial: { }, 
    reduce: function(doc, acc) { 
     if(acc.hasOwnProperty('max')) { 
      if(acc.max < doc.a) 
       acc.max = doc.a; 
     } else { 
      acc.max = doc.a 
     } 
     } 
    }) 
[ { "max" : 5230 } ] 

Dado que no existe un valor key en todo group los objetos se agrupan en un solo resultado

+0

Este enfoque sería demasiado lento. Otros inconvenientes es que ese grupo no funciona en un entorno fragmentado – Daimon

18

si tiene un índice en el campo timestsamp, encontrar el valor más alto es algo así como efficientl

db.things.find().sort({ts:-1}).limit(1) 

pero si tiene un índice es demasiada sobrecarga almacenar el máximo en una recogida selectiva puede ser bueno.

+0

@dm Sí, tengo un índice en ts y eso es exactamente lo que estoy haciendo. Sin embargo, esto tiene que suceder para cada hit web en un sitio web de tráfico relativamente alto, por lo que tiene que tener casi el mismo costo que una búsqueda por clave. De lo contrario, cuando el tráfico aumenta, las cosas van mal muy rápido. – Nitin

+0

Creo que esto devuelve un cursor. Es mejor que agregue un índice al final: db.things.find(). Sort ({ts: -1}). Limit (1) [0] – sage88

Cuestiones relacionadas