Domanda

Ho una domanda (spero veloce) sulle query mongodb su indici composti.

Dì che ho un set di dati (ad esempio, commenti) che voglio ordinare discendente per punteggio, quindi data:

{ "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"), ...}
...
.

La mia comprensione finora è che posso creare un indice composto per supportare questa query, che sembra {"score":-1,"date":-1}. (Per la chiarezza, non sto usando una data nell'indice, ma un oggetto per un ordine unico, approssimativamente basato sul tempo)

Ora, dì che voglio supportare il paging attraverso i commenti. La prima pagina è abbastanza facile, posso semplicemente attaccare un'opzione .limit(n) sulla fine del cursore. Di cosa sto facendo lottare sta continuando la ricerca.

Mi riferisco a mongodb: la guida definitiva di Kristina Chodorow. In questo libro, Kristina menziona che l'utilizzo di Skip () su set di dati di grandi dimensioni non è molto esibita e consiglia di utilizzare intervallo di query sui parametri dall'ultimo risultato visto (ad esempio l'ultima data vista).

Cosa vorrei fare è eseguire una gamma di interrogazioni che agisce su due campi, ma tratta il secondo campo come secondario al primo (proprio come l'indice è ordinato), dal momento che il mio indice composto è già ordinato esattamente nell'ordine Voglio, sembra che ci sia un modo per saltare nella ricerca puntando su un elemento specifico nell'indice e lo attraversò nell'ordine di ordinamento. Tuttavia, dalla mia comprensione della mia (ammessolmente rudimentale) delle query in MongoDB, questo non sembra possibile.

Per quanto posso vedere, ho tre opzioni:

    .
  1. Utilizzo di skip() comunque
  2. Utilizzo di $ o query o due query distinti: {$or : [{"score" : lastScore, "date" : { $lt : lastDate}}, {'score' : {$lt : lastScore}]}
  3. Utilizzo dell'opzione Query speciale $max
  4. Il numero 3 sembra il più vicino all'ideale per me, ma il testo di riferimento nota che "dovresti generalmente usare" $ lt "invece di" $ max "'.

    Per riassumere, ho alcune domande:

      .
    1. C'è un modo per eseguire l'operazione che ho descritto, che potrei aver perso? (Saltando in un indice e attraversandolo nell'ordine di ordinamento)
    2. In caso contrario, delle tre opzioni che ho descritto (o di qualsiasi hanno trascurato), il che dovrebbe (in generale in generale) fornire le prestazioni più coerenti nell'ambito dell'indice composto?
    3. Perché $ lt preferito oltre $ max nella maggior parte dei casi?
    4. Grazie in anticipo per il tuo aiuto!

È stato utile?

Soluzione

Un'altra opzione è di memorizzare score e date in un sotto-documento e quindi indicizzare il sottococumento. Ad esempio:

{
  "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 questo approccio è necessario assicurarsi che i campi nel sotto-documento BSON siano sempre memorizzati nello stesso ordine, altrimenti la query non corrisponde a ciò che ti aspetti dal momento che il confronto del tasto di indice è il confronto binario dell'intero BSON sub- Documento.

Verrei con l'uso di $max per specificare il limite superiore, in combinazione con $hint per assicurarti che il database utilizzi l'indice che desideri. Il motivo per cui $lt è in generale preferito su $max è perché $max seleziona l'indice utilizzando i limiti dell'indice specificati. Questo significa:

    .
  • L'indice scelto potrebbe non essere necessariamente la scelta migliore.
  • Se esistono più indici sugli stessi campi con ordini di ordinamento diversi, la selezione dell'indice potrebbe essere ambigua.

I punti precedenti sono coperti da ulteriori dettagli qui .

Un ultimo punto: max è equivalente a $lte, non $lt, quindi utilizzare questo approccio per il paginazione dovrai saltare sul primo documento restituito per evitare di emettere lo stesso documento due volte.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top