2010-07-09 21 views
30

Sé cómo ordenar las consultas en MongoDB por varios campos, por ejemplo, db.coll.find().sort({a:1,b:-1}).Mongo clasificación compleja?

Puedo ordenar con una función definida por el usuario; por ejemplo, suponiendo que a y b son números enteros, por la diferencia entre a y b (a-b)?

Gracias!

+1

Estoy corriendo con el mismo problema. ¿Pudo encontrar una manera de lograr esto en el lado del servidor? Preferiría no tener que hacer esto en el cliente, o agregar el campo adicional. –

Respuesta

29

ACTUALIZACIÓN: Esta respuesta parece estar desactualizada; parece que la clasificación personalizada se puede lograr más o menos utilizando el $project function of the aggregation pipeline para transformar los documentos de entrada antes de la clasificación. Ver también la respuesta de @Ari.

No creo que esto sea posible directamente; el sort documentation ciertamente no menciona ninguna forma de proporcionar una función de comparación personalizada.

Probablemente sea mejor que haga la clasificación en el cliente, pero si realmente está decidido a hacerlo en el servidor, puede usar db.eval() para organizar la ejecución en el servidor (si su cliente lo admite).

del lado del servidor para ordenar:

db.eval(function() { 
    return db.scratch.find().toArray().sort(function(doc1, doc2) { 
    return doc1.a - doc2.a 
    }) 
}); 

Versus el equivalente tipo de cliente:

db.scratch.find().toArray().sort(function(doc1, doc2) { 
    return doc1.a - doc2.b 
}); 

Tenga en cuenta que también es posible ordenar a través de un aggregation pipeline y por el $orderby operator (es decir, además .sort()) sin embargo, ninguna de estas formas le permite proporcionar una función de clasificación personalizada.

+2

Sí. Después de seguir investigando, descubrí que se ha presentado un RFE para permitir que las funciones de conveniencia hagan exactamente esto. Definitivamente no me gusta el aspecto de 'toArray()' para mis documentos ~ 10m, pero aparentemente ese es el estado de las cosas. – gilesc

+0

Hola @gilesc. ¿Podrías decirme cómo usaste exactamente 'RFE archivado' en detalle? Estoy en la misma situación. – LotusH

+1

@Wasabi Creo que se estaba refiriendo a esto: https://jira.mongodb.org/browse/SERVER-153 No es posible, pero hay un boleto abierto donde están considerando implementarlo. Pero ha estado abierto durante años, por lo que no estoy seguro si alguna vez sucederá. – rmarscher

11

¿Por qué no crear el campo con esta operación y ordenarlo?

+3

Aún necesito acceso aa y b de forma individual. Entonces tendría que crear un tercer campo. Eso funcionaría para mi aplicación, pero como principio general sería una muy mala política. Suponiendo que tuviera varios campos enteros, habría una explosión combinatoria de atributos derivados (a-b), (a-c), (a-d) ... Incluso con un solo campo como este, es realmente un desperdicio de espacio especialmente para una gran colección. Estoy votando y si nadie más responde aceptando, pero tiene que haber una manera mejor. En SQL esto es tan fácil como 'SELECT * FROM coll ORDER BY (a-b)'. – gilesc

+1

Tenga en cuenta que aunque puede hacer esto en SQL, no es muy eficiente. La base de datos tiene que buscar todos los valores a y b, calcular a-b, ordenar los resultados y devolver los registros asociados. Con Mongo esto significaría cargar todos los documentos en la memoria si no tiene un índice en a y b. Si crea un nuevo campo, puede crear un índice en este campo, lo que hará que esta consulta sea realmente rápida. – konrad

+0

Gran idea. Siempre que el valor de la posición de un registro esté localizado en los datos del registro, esto amortiza perfectamente el costo de calcular el género en la inserción/actualización. – DoctorPangloss

15

encontré con esto y esto es lo que ocurrió:

db.collection.aggregate([ 
    { 
    $project: { 
     difference: { $subtract: ["$a", "$b"] } 
     // Add other keys in here as necessary 
    } 
    }, 
    { 
    $sort: { difference: -1 } 
    } 
])