Per rispondere direttamente alla tua domanda, sì, è il modo più efficiente. Ma penso che dobbiamo chiarire perché sia così.
come suggerito nelle alternative, l'unica cosa che la gente sta guardando è "l'ordinamento" i risultati prima di passare ad una fase $group
e che cosa stanno guardando è il valore "timestamp", in modo che ci si vuole fare assicurarsi che tutto sia in ordine "timestamp", in modo da qui il modulo:
db.temperature.aggregate([
{ "$sort": { "station": 1, "dt": -1 } },
{ "$group": {
"_id": "$station",
"result": { "$first":"$dt"}, "t": {"$first":"$t"}
}}
])
E come detto si sarà ovviamente vuole un indice per riflettere che, al fine di rendere il tipo efficiente:
Tuttavia e thi s è il vero punto.Ciò che sembra essere stato trascurato da altri (se non è così per te) è che probabilmente tutti questi dati sono stati inseriti già in ordine cronologico, in quanto ogni lettura è registrata come aggiunta.
Così la bellezza di questo è il campo _id
(il valore predefinito è ObjectId
) è già in ordine "timestamp", così come si fa in realtà contiene un valore di tempo e questo rende la dichiarazione possibile:
db.temperature.aggregate([
{ "$group": {
"_id": "$station",
"result": { "$last":"$dt"}, "t": {"$last":"$t"}
}}
])
E lo è più veloce. Perché? Bene, non è necessario selezionare un indice (codice aggiuntivo da richiamare), inoltre non è necessario "caricare" l'indice oltre al documento.
Abbiamo già sanno i documenti siano in ordine (da _id
) in modo che i $last
confini sono perfettamente valide. Si sta eseguendo comunque la scansione di tutto e si potrebbe anche eseguire una query "intervallo" sui valori _id
come ugualmente validi per due date.
L'unica cosa vera da dire qui, è che nel "mondo reale" utilizzo, potrebbe essere solo più pratico per voi di $match
tra intervalli di date quando si fa questo tipo di accumulo invece di ottenere la "prima "e" last "_id
valori per definire un" intervallo "o qualcosa di simile nell'utilizzo effettivo.
Quindi, dov'è la prova di questo? Beh, è abbastanza facile da riprodurre, quindi ho solo fatto in modo da generare un po 'di dati di esempio:
var stations = [
"AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL",
"GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA",
"ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE",
"NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK",
"OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT",
"VA", "WA", "WV", "WI", "WY"
];
for (i=0; i<200000; i++) {
var station = stations[Math.floor(Math.random()*stations.length)];
var t = Math.floor(Math.random() * (96 - 50 + 1)) +50;
dt = new Date();
db.temperatures.insert({
station: station,
t: t,
dt: dt
});
}
Il mio hardware (computer portatile da 8 GB con disco spinny, che non è stellare, ma certamente adeguato) in esecuzione ogni forma di la dichiarazione mostra chiaramente una pausa notevole con la versione che utilizza un indice e un ordinamento (stesse chiavi sull'indice dell'istruzione sort). È solo una piccola pausa, ma la differenza è abbastanza significativa da notare.
Anche guardando in uscita spiegare (versione 2.6 in su, o in realtà c'è in 2.4.9 anche se non documentato) si può vedere la differenza in quanto, anche se il $sort
è ottimizzato fuori a causa della presenza di un indice, il tempo impiegato sembra essere con la selezione dell'indice e quindi il caricamento delle voci indicizzate. L'inclusione di tutti i campi per una query dell'indice "coperta" "coperta" non fa alcuna differenza.
Anche per la cronologia, indicizzazione puramente della data e solo l'ordinamento sui valori di data dà lo stesso risultato. Forse leggermente più veloce, ma ancora più lento del modulo indice naturale senza l'ordinamento.
Quindi, fintanto che si può tranquillamente "range" sulle prima e ultimi_id
valori, allora è vero che utilizzando l'indice naturale sul ordine di inserimento è in realtà il modo più efficace per farlo. Il tuo chilometraggio nel mondo reale può variare a seconda che questo sia pratico o meno per te e potrebbe semplicemente risultare più conveniente implementare l'indice e l'ordinamento alla data.
Ma se eri felice con l'utilizzo di _id
gamme o superiori al "ultima" _id
nella query, allora forse un Tweak per ottenere i valori insieme con i vostri risultati in modo da poter in serbo fatto e utilizzare le informazioni in query successive:
db.temperature.aggregate([
// Get documents "greater than" the "highest" _id value found last time
{ "$match": {
"_id": { "$gt": ObjectId("536076603e70a99790b7845d") }
}},
// Do the grouping with addition of the returned field
{ "$group": {
"_id": "$station",
"result": { "$last":"$dt"},
"t": {"$last":"$t"},
"lastDoc": { "$last": "$_id" }
}}
])
e se si fosse in realtà "in seguito" i risultati del genere, allora è possibile determinare il valore massimo di ObjectId
dai risultati e usarlo nella prossima interrogazione.
In ogni caso, divertiti a giocare con quello, ma di nuovo Sì, in questo caso quella query è il modo più veloce.
la risposta che hai accettato da NeilLunn è effettivamente errata. Non è garantito che l'ordine naturale sia un ordine di inserzione (ad eccezione delle collezioni con limite) e _id è garantito che aumenti in modo monotono se * tutti * delle macchine client sono sincronizzati nel tempo. –