Diferença entre as chamadas find e findone do MongoDB


34

Estou trabalhando em um projeto e não tenho certeza se existe uma diferença entre a maneira como o findcursor funciona e a maneira como o findOnecursor funciona. O findOne é apenas um invólucro find().limit(1)? Eu estava procurando por ele e talvez alguém saiba se o mongodb tem um método especial para isso ou não. Estou trabalhando com a API do PHP para mongodb, se isso faz alguma diferença.

Respostas:


33

Baseado em meus próprios benchmarks, find().limit(1)é uma ordem de magnitude mais rápida que findOne().

Há um erro na documentação do MongoDB ou um erro no findOne(). findOne()executa mais como find().limit(N)N onde é o número de documentos que a consulta retornaria. Eu descobri isso enquanto tentava descobrir por que minhas consultas simples eram tão lentas!

update: resposta de um engenheiro de 10gen (MongoDB):

As duas consultas que você está executando são muito diferentes. Uma consulta de busca retorna um cursor, este é essencialmente um cenário sem operação, pois nenhum dado real é retornado (apenas as informações do cursor). Se você chamar findOne, estará retornando os dados e fechando o cursor. Os documentos definitivamente devem ser mais claros :-)

Atualização: De fato, se o find().limit(1)documento for recuperado, as ordens de magnitude da diferença de velocidade parecerão desaparecer. Além disso, não consegui reproduzir a principal diferença de velocidade com o driver JavaScript do MongoDB. Originalmente, fiz um benchmarking usando o driver Java do MongoDB.


11
Ótima descoberta. Porém, uma pergunta importante: seus benchmarks consideram as operações extras com as quais você teria que fazer find().limit(1)no decorrer da programação normal (como recuperar os dados e fechar o cursor) que são findOne()automaticamente úteis para você?
Nick Chammas

@ Nick: Eu acho que operações extras foram cobertas. Eu estava encontrando um documento aleatório ( cookbook.mongodb.org/patterns/random-attribute ), obtendo o documento com .next () e removendo-o da coleção. Eu não fiz manualmente Feche os cursores ...
Leftium

@Leftium então eu preciso perguntar é mais rápido para fazer um find.limit (1) e, em seguida, obter o valor cursur ou é mais rápido para fazer um findOne ()
WojonsTech

2
@WojonsTech: uma referência rápida em JS mostra que findOne () é realmente mais rápido. Os resultados podem variar de acordo com o driver / plataforma. Por exemplo, não pude reproduzir as ordens de magnitude da diferença de velocidade em JS que observei originalmente com o driver Java.
Leftium 7/11/11

2
Leftium, gostaria de editar sua resposta para enfatizar que, quando você realmente recupera o documento (o que normalmente faria), as duas funções são realmente idênticas, assim como a documentação declara. No momento, alguém provavelmente lerá a linha em negrito no início da sua resposta e concluirá que, se quiser recuperar um documento, findOne()é pior do que o find().limit(1)que está incorreto.
Nick Chammas

5

findOne()é realmente açúcar sintático para find().limit(1), uma vez que você está realmente recuperar o documento (ao invés de apenas retornar o cursor com find()).

Consulte a resposta e as atualizações do Leftium para obter mais detalhes.


ok obrigado eu não gosto de usar funções synimus na minha programação prefiro colocar um limite para mim mesmo, então todo o meu código é fácil de rastrear.
WojonsTech #

11
Na verdade, nos benchmarks findOne () um pouco mais rápido que find (). Limit (1).
Vladimir

@ DairT'arg - Se você possui fontes ou dados para fazer backup dessa reivindicação, publique uma resposta com todos os detalhes! Pelo que reuni até agora, eles devem ser idênticos desde que você recupere o documento nos dois casos.
25412 Nick Chammas

3

O código fonte pode ajudar bastante.

É java, mas acho que também pode ajudar.

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

E aqui está find()

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

Como podemos ver que as findOne()chamadas find()em si mesmo, recebe toda a DBOjectem ie, em seguida, retornar o primeiro.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.