Unterschied zwischen MongoDBs find und findone Aufrufen


34

Ich arbeite an einem Projekt und bin mir nicht sicher, ob es einen Unterschied zwischen der Funktionsweise des findCursors und der Funktionsweise des findOneCursors gibt. Ist findOne nur ein Wrapper für find().limit(1)? Ich habe mich danach umgesehen und vielleicht weiß jemand, ob Mongodb eine spezielle Methode dafür hat oder nicht. Ich arbeite mit der PHP-API für Mongodb, wenn das einen Unterschied macht.

Antworten:


33

Basierend auf meinen eigenen Benchmarks find().limit(1)ist es um Größenordnungen schneller als findOne().

Es liegt entweder ein Fehler in der MongoDB-Dokumentation oder ein Fehler in vor findOne(). findOne()verhält sich eher so, find().limit(N)als wäre N die Anzahl der Dokumente, die die Abfrage zurückgeben würde. Ich habe das herausgefunden, als ich versuchte herauszufinden, warum meine einfachen Abfragen so langsam waren!

Update: Antwort eines 10gen (MongoDB) Ingenieurs:

Die beiden Abfragen, die Sie ausführen, sind sehr unterschiedlich. Eine Suchabfrage gibt einen Cursor zurück. Dies ist im Wesentlichen ein Szenario ohne Operation, da keine tatsächlichen Daten zurückgegeben werden (nur die Cursorinformationen). Wenn Sie findOne aufrufen, geben Sie die Daten tatsächlich zurück und schließen den Cursor. Die Dokumente sollten auf jeden Fall klarer sein :-)

Update: Wenn das find().limit(1)Dokument abgerufen wird, scheint der Geschwindigkeitsunterschied um Größenordnungen zu verschwinden. Außerdem konnte ich den großen Geschwindigkeitsunterschied mit dem MongoDB-JavaScript-Treiber nicht reproduzieren. Ich habe ursprünglich mit dem MongoDB Java-Treiber verglichen.


1
Toller Fund. Wichtige Frage: Berücksichtigen Ihre Benchmarks die zusätzlichen Vorgänge, die Sie find().limit(1)im Verlauf der normalen Programmierung ausführen müssen (z. B. das tatsächliche Abrufen der Daten und Schließen des Cursors), findOne()die ohnehin automatisch für Sie ausgeführt werden?
Nick Chammas

@ Nick: Ich denke, zusätzliche Operationen wurden abgedeckt. Ich fand ein zufälliges Dokument ( cookbook.mongodb.org/patterns/random-attribute ), holte das Dokument mit .next () und entfernte es aus der Sammlung. Ich habe keine Cursor manuell geschlossen ...
Leftium

@Leftium dann muss ich fragen, ob es schneller ist, find.limit (1) zu machen und dann den cursur-Wert zu erhalten, oder ob es schneller ist, findone () zu machen
WojonsTech

2
@ WojonsTech: Ein schneller Benchmark in JS zeigt, dass findOne () tatsächlich schneller ist. Die Ergebnisse können jedoch je nach Treiber / Plattform variieren. Zum Beispiel konnte ich die Größenordnungs-Geschwindigkeitsdifferenz in JS nicht reproduzieren, die ich ursprünglich mit dem Java-Treiber beobachtet hatte.
Leftium

2
Leftium, ich würde Ihre Antwort bearbeiten, um zu betonen, dass beim tatsächlichen Abrufen des Dokuments (was normalerweise der Fall ist) die beiden Funktionen identisch sind, genau wie in der Dokumentation angegeben. Im Moment wird wahrscheinlich jemand die fett gedruckte Zeile am Anfang Ihrer Antwort lesen und daraus schließen, dass, wenn er ein Dokument abrufen möchte, dies findOne()schlimmer ist als find().limit(1), was falsch ist.
Nick Chammas

5

findOne()ist in der Tat syntaktischer Zucker für find().limit(1), da Sie das Dokument tatsächlich abrufen (im Gegensatz dazu, nur den Cursor mit zurückzugeben find()).

Weitere Informationen finden Sie in der Antwort und den Updates von Leftium .


Okay, danke. Ich mag es nicht, Synimus-Funktionen in meiner Programmierung zu verwenden. Ich würde lieber ein Limit setzen, nur damit mein gesamter Code leicht zu finden ist.
WojonsTech

1
Tatsächlich ist findOne () in Benchmarks etwas schneller als find (). Limit (1).
Vladimir

@ DairT'arg - Wenn Sie Quellen oder Daten haben, um diese Behauptung zu stützen, senden Sie auf jeden Fall eine Antwort mit den Details! Nach dem, was ich bisher gesammelt habe, sollten sie identisch sein, solange Sie das Dokument in beiden Fällen abrufen.
Nick Chammas

3

Der Quellcode kann sehr hilfreich sein.

Es ist Java, aber ich denke, es kann auch helfen.

Die 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;
}

Und hier ist find()

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

Wie wir sehen können, findOne()ruft das find()in sich selbst auf, holt alles DBOjectein iund gibt dann das erste zurück.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.