Todos os meus registros têm um campo chamado "fotos". Este campo é uma matriz de seqüências de caracteres.
Agora eu quero os 10 registros mais recentes em que essa matriz NÃO está vazia.
Eu pesquisei por aí, mas, estranhamente, não encontrei muito sobre isso. Eu li a opção $ where, mas queria saber o quão lento isso é para as funções nativas e se há uma solução melhor.
E mesmo assim, isso não funciona:
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
Retorna nada. Sair this.pictures
sem o bit de comprimento funciona, mas também retorna registros vazios, é claro.
mongoengine
ME.find({ pictures: { $gt: [] } })
É PERIGOSO, mesmo nas versões mais recentes do MongoDB. Se você tiver um índice no seu campo de lista e esse índice for utilizado durante a consulta, você obterá resultados inesperados. Por exemplo:db.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()
retorna o número certo, enquantodb.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count()
retorna0
.Depois de mais algumas pesquisas, especialmente nos documentos do mongodb e em partes intrigantes, esta foi a resposta:
fonte
pictures
campo.Isso também pode funcionar para você:
fonte
pictures.2
existe, maspictures.1
não existe ?$exists
operador é um booleano, não um deslocamento. @tenbatsu deve estar usando emtrue
vez de1
.Would there ever be a case where pictures.2 exists but pictures.1 does not?
Sim, pode ser esse o caso.pictures
fosse um sub-documento, não uma matriz. por exemplopictures: {'2': 123}
pictures
.Você se preocupa com duas coisas ao consultar - precisão e desempenho. Com isso em mente, testei algumas abordagens diferentes no MongoDB v3.0.14.
TL; DR
db.doc.find({ nums: { $gt: -Infinity }})
é o mais rápido e confiável (pelo menos na versão MongoDB que testei).EDIT: Isso não funciona mais no MongoDB v3.6! Veja os comentários nesta postagem para uma solução em potencial.
Configuração
Inseri 1k documentos sem um campo de lista, 1k documentos com uma lista vazia e 5 documentos com uma lista não vazia.
Reconheço que essa escala não é suficiente para levar o desempenho tão a sério quanto nos testes abaixo, mas é suficiente para apresentar a correção de várias consultas e o comportamento dos planos de consulta escolhidos.
Testes
db.doc.find({'nums': {'$exists': true}})
retorna resultados incorretos (pelo que estamos tentando realizar).-
db.doc.find({'nums.0': {'$exists': true}})
retorna resultados corretos, mas também é lento usando uma verificação completa da coleção (COLLSCAN
estágio de aviso na explicação).-
db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}})
retorna resultados incorretos. Isso ocorre devido a uma verificação de índice inválida, que não avança nenhum documento. Provavelmente será preciso, mas lento sem o índice.-
db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}})
retorna resultados corretos, mas o desempenho é ruim. Tecnicamente, ele faz uma varredura de índice, mas ainda avança todos os documentos e precisa filtrar por eles).-
db.doc.find({'nums': { $exists: true, $ne: [] }})
retorna resultados corretos e é um pouco mais rápido, mas o desempenho ainda não é o ideal. Ele usa o IXSCAN, que apenas avança documentos com um campo de lista existente, mas depois filtra as listas vazias uma a uma.-
db.doc.find({'nums': { $gt: [] }})
É PERIGOSO PORQUE DEPENDENDO DO ÍNDICE USADO PODE DAR RESULTADOS INESPERADOS. Isso ocorre devido a uma verificação de índice inválida que não avança nenhum documento.-
db.doc.find({'nums.0’: { $gt: -Infinity }})
retorna resultados corretos, mas apresenta desempenho ruim (usa uma verificação completa da coleção).-
db.doc.find({'nums': { $gt: -Infinity }})
surpreendentemente, isso funciona muito bem! Ele fornece os resultados certos e é rápido, avançando 5 documentos da fase de verificação do índice.fonte
seen_events
matriz String, que também é indexada. Pesquisando com{ $gt: -Infinity }
, recebo imediatamente 0 documentos. Usando{ $exists: true, $ne: [] }
eu obtenho os 1,2 milhões de documentos mais prováveis, com muito tempo sendo desperdiçado no estágio FETCH: gist.github.com/N-Coder/b9e89a925e895c605d84bfeed648d82cdb.test_collection.find({"seen_events.0": {$exists: true}})
é ruim porque ele usa uma varredura coleção 2..db.test_collection.find({seen_events: {$exists: true, $ne: []}})
É . ruim porque sua IXSCAN corresponde a todos os documentos e, em seguida, a filtragem é realizada na fase lenta FETCH 3. o mesmo vale paradb.test_collection.find({seen_events: {$exists: true, $not: {$size: 0}}})
4. Todos os outros consultas retornam resultados inválidos..seen_events
contêm cordas, você pode usar este:db.test_collection.find({seen_events: {$gt: ''}}).count()
. Para confirmar se o desempenho está bom, confiradb.test_collection.find({seen_events: {$gt: ''}}).explain(true).executionStats
. Você provavelmente pode impor que os eventos vistos são strings via validação de esquema: docs.mongodb.com/manual/core/schema-validationComeçando com a versão 2.6, outra maneira de fazer isso é comparar o campo com uma matriz vazia:
Testando-o no shell:
Portanto, inclui adequadamente os documentos em que
pictures
há pelo menos um elemento de matriz e exclui os documentos em quepictures
há uma matriz vazia, não uma matriz ou ausente.fonte
db.ME.createIndex({ pictures: 1 })
e depoisdb.ME.find({pictures: {$gt: []}})
retornará zero resultados, pelo menos no MongoDB v3.0.14Você pode usar qualquer um dos seguintes para conseguir isso.
Ambos também cuidam de não retornar um resultado para objetos que não possuem a chave solicitada:
fonte
Recupere todos e somente os documentos em que 'figuras' é uma matriz e não está vazia
Se você estiver usando uma versão do MongoDb anterior à 3.2 , use em
$type: 4
vez de$type: 'array'
. Observe que esta solução nem usa $ size , portanto, não há problemas com índices ("As consultas não podem usar índices para a parte $ size de uma consulta")Outras soluções, incluindo estas (resposta aceita):
são errado , porque eles retornam documentos, mesmo que, por exemplo, 'retratos' é
null
,undefined
, 0, etc.fonte
Use o
$elemMatch
operador: de acordo com a documentação$elemMatches
garante que o valor seja uma matriz e que não esteja vazio. Portanto, a consulta seria algo comoME.find({ pictures: { $elemMatch: {$exists: true }}})
PS Uma variante desse código é encontrada no curso M121 da MongoDB University.
fonte
Você também pode usar o método auxiliar Existe no operador Mongo.
fonte
use o $ where e passe o this.field_name.length que retorna o tamanho do campo da matriz e verifique-o comparando com o número. se qualquer matriz tiver algum valor além do tamanho da matriz, deve ser pelo menos 1. para que todo o campo da matriz tenha comprimento maior que um, significa que há alguns dados nessa matriz
fonte
Simples assim, isso funcionou para mim.
fonte