Differenza tra le chiamate find e findone di MongoDB


34

Sto lavorando a un progetto e non sono sicuro che ci sia una differenza tra il modo in cui il findcursore funziona e il modo in cui il findOnecursore funziona. FindOne è solo un wrapper per find().limit(1)? Lo stavo cercando e forse qualcuno sa se mongodb ha un metodo speciale o no. Sto lavorando con l'API PHP per mongodb se questo fa la differenza.

Risposte:


33

Sulla base dei miei parametri di riferimento, gli find().limit(1)ordini di grandezza sono più veloci di findOne().

C'è un errore nella documentazione di MongoDB o un errore in findOne(). findOne()esegue di più come find().limit(N)dove N è il numero di documenti che la query restituirebbe. L'ho capito mentre cercavo di capire perché le mie semplici domande fossero così lente!

aggiornamento: risposta di un ingegnere 10gen (MongoDB):

Le due query che stai eseguendo sono molto diverse. Una query di ricerca restituisce un cursore, questo è essenzialmente uno scenario senza operazioni, poiché non vengono restituiti dati effettivi (solo le informazioni del cursore). Se chiami findOne, stai effettivamente restituendo i dati e chiudendo il cursore. I documenti dovrebbero essere sicuramente più chiari :-)

Aggiornamento: in effetti, se il find().limit(1)documento viene recuperato, gli ordini di differenza di velocità della grandezza sembrano scomparire. Inoltre, non sono riuscito a riprodurre la maggiore differenza di velocità con il driver JavaScript MongoDB. Inizialmente ho eseguito il benchmarking utilizzando il driver Java MongoDB.


1
Grande scoperta. Domanda importante, però: i tuoi benchmark tengono conto delle operazioni extra che avresti a che fare find().limit(1)nel corso della normale programmazione (come recuperare effettivamente i dati e chiudere il cursore) che findOne()fanno comunque automaticamente per te?
Nick Chammas,

@ Nick: penso che siano state coperte operazioni extra. Stavo trovando un documento casuale ( cookbook.mongodb.org/patterns/random-attribute ), ottenendo il documento con .next () e rimuovendolo dalla raccolta. Non ho chiuso manualmente alcun cursore ...
Leftium

@Leftium allora devo chiederti se è più veloce fare un find.limit (1) e poi ottenere il valore del cursore o è più veloce fare un findone ()
WojonsTech

2
@WojonsTech: un rapido benchmark in JS mostra che findOne () è in realtà più veloce. I risultati possono variare a seconda del driver / della piattaforma. Ad esempio, non sono riuscito a riprodurre gli ordini di differenza di velocità in grandezza in JS che ho osservato inizialmente con il driver Java.
Leftium,

2
Leftium, vorrei modificare la tua risposta per sottolineare che quando recuperi effettivamente il documento (cosa che normalmente faresti), le due funzioni sono effettivamente identiche, proprio come afferma la documentazione. In questo momento qualcuno probabilmente leggerà la riga in grassetto all'inizio della tua risposta e concluderà che se vogliono recuperare un documento, findOne()è peggio di find().limit(1), che non è corretto.
Nick Chammas,

5

findOne()è davvero zucchero sintattico per find().limit(1), dato che stai effettivamente recuperando il documento (invece di riportare il cursore confind() ).

Vedi la risposta e gli aggiornamenti di Leftium per maggiori dettagli.


okay grazie non mi piace usare le funzioni di synimus nella mia programmazione piuttosto limiterei me stesso solo così tutto il mio codice è facile da rintracciare.
WojonsTech,

1
In realtà nei benchmark findOne () un po 'più veloce di find (). Limit (1).
Vladimir

@ DairT'arg - Se si dispone di fonti o dati per il backup di questo reclamo, inviare una risposta con i dettagli! Da quello che ho raccolto finora, dovrebbero essere identici purché tu stia recuperando il documento in entrambi i casi.
Nick Chammas,

3

Il codice sorgente può aiutare molto.

È java ma immagino che possa aiutare anche.

Il findOne(),

DBObject findOne(DBObject o, DBObject fields, DBObject orderBy, ReadPreference readPref,
                 long maxTime, TimeUnit maxTimeUnit) {

    QueryOpBuilder queryOpBuilder = new QueryOpBuilder().addQuery(o).addOrderBy(orderBy)
                                                        .addMaxTimeMS(MILLISECONDS.convert(maxTime, maxTimeUnit));

    if (getDB().getMongo().isMongosConnection()) {
        queryOpBuilder.addReadPreference(readPref);
    }

    Iterator<DBObject> i = find(queryOpBuilder.get(), fields, 0, -1, 0, getOptions(), readPref, getDecoder());

    DBObject obj = (i.hasNext() ? i.next() : null);
    if ( obj != null && ( fields != null && fields.keySet().size() > 0 ) ){
        obj.markAsPartialObject();
    }
    return obj;
}

Ed eccolo qui find()

public DBCursor find( DBObject ref ){
    return new DBCursor( this, ref, null, getReadPreference());
}

Come possiamo vedere che findOne()chiama find()in se stesso, ottiene tutto DBOjectdentro ie quindi restituisce il primo.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.