Pregunta

Tengo un (esperemos rápido) pregunta sobre MongoDB consultas en los índices compuestos.

Decir que tengo un conjunto de datos (por ejemplo, comentarios) que me desea ordenar de forma descendente de puntuación y, a continuación, la fecha:

{ "score" : 10, "date" : ISODate("2014-02-24T00:00:00.000Z"), ...}
{ "score" : 10, "date" : ISODate("2014-02-18T00:00:00.000Z"), ...}
{ "score" : 10, "date" : ISODate("2014-02-12T00:00:00.000Z"), ...}
{ "score" : 9, "date" : ISODate("2014-02-22T00:00:00.000Z"), ...}
{ "score" : 9, "date" : ISODate("2014-02-16T00:00:00.000Z"), ...}
...

Mi entendimiento es que puedo hacer un índice compuesto para apoyar a esta consulta, que se parece a {"score":-1,"date":-1}.(En aras de la claridad, no estoy utilizando una fecha en el índice, pero un ObjectID únicos, aproximadamente basado en el tiempo de la orden)

Ahora, supongamos que queremos el apoyo de paginación a través de los comentarios.La primera página es bastante fácil, solo puedo meter un .limit(n) opción en el extremo del cursor.Lo que yo estoy luchando con la que se sigue la búsqueda.

Me estoy refiriendo a MongoDB:La Guía Definitiva por Kristina Chodorow.En este libro, Kristina menciona que el uso de skip() sobre grandes conjuntos de datos no es muy eficiente, y recomienda el uso de las consultas de rango en los parámetros de la última visto el resultado (por ejemplo.el último visto la fecha).

Lo que me gustaría hacer es realizar una serie de consultas que actúa en dos campos, pero se trata del segundo campo como secundaria a la primera (al igual que el índice está ordenada.) Desde mi índice compuesto ya está ordenada en el orden exacto que quiero, parece que debe haber alguna manera de saltar en la búsqueda apunta a un elemento específico en el índice y se atravesaba en el orden de clasificación.Sin embargo, desde mi (ciertamente rudimentario) la comprensión de las consultas en MongoDB esto no parece posible.

Tan lejos como puedo ver, tengo tres opciones:

  1. El uso de skip() de todos modos
  2. El uso de un $o consulta o dos consultas: {$or : [{"score" : lastScore, "date" : { $lt : lastDate}}, {'score' : {$lt : lastScore}]}
  3. El uso de la $max especial de la opción de consulta de

Número 3 parece la más cercana a la ideal para mí, pero en el texto de referencia señala que 'generalmente debe usar "$lt" en lugar de "$max"'.

Para resumir, tengo un par de preguntas:

  1. ¿Hay alguna forma de realizar la operación que he descrito, que puede haber perdido?(Saltando en un índice y que atraviesan en el orden de clasificación)
  2. Si no, una de las tres opciones que se describen (o cualquier otro que yo haya pasado por alto), que (muy general) dar el rendimiento más coherente bajo el índice compuesto?
  3. ¿Por qué es de $lt preferida de más de $max en la mayoría de los casos?

Gracias de antemano por su ayuda!

¿Fue útil?

Solución

Otra opción es almacenar score y date en un sub-documento y, a continuación, el índice de la sub-documento.Por ejemplo:

{
  "a" : { "score" : 9,
          "date" : ISODate("2014-02-22T00:00:00Z") },
  ...
}

db.foo.ensureIndex( { a : 1 } )

db.foo.find( { a : { $lt : { score : lastScore,
                             date: lastDate } } } ).sort( { a : -1 } )

Con este enfoque, usted necesita para asegurarse de que los campos en que el HIJO de sub-documento se almacenan siempre en el mismo orden, de lo contrario la consulta no coincidan con lo que espera desde el índice de la clave de comparación comparación binaria de todo el BHIJO sub-documento.

Me gustaría ir con el uso de $max para especificar el límite superior, en conjunto con $hint para asegurarse de que la base de datos utiliza el índice que desee.La razón por la que $lt en general se prefiere sobre $max es porque $max selecciona el índice usando el índice especificado límites.Esto significa:

  • el índice elegido puede no ser necesariamente la mejor opción.
  • si existen varios índices en los mismos campos con diferentes criterios de ordenación, la selección del índice puede ser ambiguo.

Los puntos anteriores son cubiertos en más detalle aquí.

Un último punto: max es equivalente a $lte, no $lt, por lo que el uso de este enfoque para la paginación deberá saltar sobre el primer documento devuelto para evitar transmitir el mismo documento dos veces.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top