2010-07-09 27 views
30

so come ordinare le query in MongoDB da molteplici campi, per esempio, db.coll.find().sort({a:1,b:-1}).Ordinamento complesso Mongo?

Posso ordinare con una funzione definita dall'utente; ad esempio, supponendo che aeb siano numeri interi, in base alla differenza tra a e b (a-b)?

Grazie!

+1

sto correndo lo stesso problema. Sei riuscito a trovare un modo per farlo sul lato server? Preferirei non doverlo fare sul client o aggiungere il campo aggiuntivo. –

risposta

29

UPDATE: Questa risposta sembra essere fuori moda; sembra che l'ordinamento personalizzato possa essere più o meno raggiunto utilizzando $project function of the aggregation pipeline per trasformare i documenti di input prima dell'ordinamento. Vedi anche la risposta di @ Ari.

Non credo che questo sia possibile direttamente; il sort documentation non menziona certamente alcun modo per fornire una funzione di confronto personalizzata.

Probabilmente stai meglio nel genere nel client, ma se sei davvero determinato a farlo sul server potresti essere in grado di usare db.eval() per organizzare l'ordinamento sul server (se il tuo cliente lo supporta).

lato server sorta:

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

Versus l'equivalente sul lato client sorta:

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

Si noti che è anche possibile ordinare tramite un aggregation pipeline e dal $orderby operator (vale a dire, oltre a .sort()) tuttavia nessuno di questi modi consente di fornire una funzione di ordinamento personalizzata.

+2

Sì. Dopo ulteriori scavi, ho scoperto che è stato archiviato un file RFE per consentire alle funzioni di comodità di fare esattamente questo. Sicuramente non mi piace l'aspetto di 'toArray()' per i miei documenti ~ 10m, ma apparentemente è lo stato delle cose. – gilesc

+0

Ciao @gilesc. Per favore, dimmi come hai usato esattamente "RFE archiviato" in dettaglio? Sono nella stessa situazione. – LotusH

+1

@Wasabi Penso che si riferisse a questo: https://jira.mongodb.org/browse/SERVER-153 Non è possibile, ma c'è un ticket aperto dove stanno pensando di implementarlo. Ma è stato aperto per anni, quindi non sono sicuro che succederà mai. – rmarscher

11

Perché non creare il campo con questa operazione e sorta su di esso?

+3

Ho ancora bisogno di accedere a aeb individualmente. Quindi dovrei creare un terzo campo. Che funzionerebbe per la mia applicazione, ma come principio generale sarebbe davvero una cattiva politica. Supponendo Ho avuto diversi campi di numeri interi, ci sarebbe stata un'esplosione combinatoria di attributi derivati ​​(A-B), (A-C), (a-d) ... Anche con un solo campo come questo, è davvero uno spreco di spazio soprattutto per una grande collezione. Sto svendendo e se nessun altro risponde accettando, ma ci deve essere un modo migliore. In SQL questo è facile come 'SELECT * FROM coll ORDER BY (a-b)'. – gilesc

+1

Si noti che, sebbene sia possibile farlo in SQL, non è molto efficiente. Il database deve recuperare tutti i valori a e b, calcolare a-b, ordinare i risultati e restituire i record associati. Con Mongo questo significherebbe caricare tutti i documenti in memoria se non si dispone di un indice su aeb. Se crei un nuovo campo, puoi creare un indice su questo campo, che renderà questa query molto veloce. – konrad

+0

Ottima idea. Finché il valore della posizione di un record è localizzato nei dati del record stesso, questo ammortizza perfettamente il costo del calcolo dell'ordinamento sull'inserimento/aggiornamento. – DoctorPangloss

15

imbattuto in questo e questo è ciò che mi si avvicinò con:

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