Todos mis registros tienen un campo llamado "imágenes". Este campo es una matriz de cadenas.
Ahora quiero los 10 registros más nuevos donde esta matriz NO ESTÁ vacía.
He buscado en Google, pero curiosamente no he encontrado mucho en esto. Leí en la opción $ where, pero me preguntaba qué tan lento es para las funciones nativas, y si hay una mejor solución.
E incluso entonces, eso no funciona:
ME.find({$where: 'this.pictures.length > 0'}).sort('-created').limit(10).execFind()
No devuelve nada Salir this.pictures
sin el bit de longitud funciona, pero también devuelve registros vacíos, por supuesto.
mongoengine
ME.find({ pictures: { $gt: [] } })
ES PELIGROSO, incluso en las versiones más nuevas de MongoDB. Si tiene un índice en su campo de lista y ese índice se utiliza durante la consulta, obtendrá resultados inesperados. Por ejemplo:db.doc.find({'nums': { $gt: [] }}).hint({ _id: 1 }).count()
devuelve el número correcto, mientras quedb.doc.find({'nums': { $gt: [] }}).hint({ nums: 1 }).count()
devuelve0
.Después de mirar un poco más, especialmente en los documentos mongodb, y trozos desconcertantes juntos, esta fue la respuesta:
fuente
pictures
campo.Esto también podría funcionar para usted:
fuente
pictures.2
exista peropictures.1
no exista ?$exists
operador es un booleano, no un desplazamiento. @tenbatsu debería estar usando entrue
lugar de1
.Would there ever be a case where pictures.2 exists but pictures.1 does not?
Sí, ese caso podría suceder.pictures
es un sub-documento, no una matriz. por ejemplopictures: {'2': 123}
pictures
.Al realizar consultas, le interesan dos cosas: precisión y rendimiento. Con eso en mente, probé algunos enfoques diferentes en MongoDB v3.0.14.
TL; DR
db.doc.find({ nums: { $gt: -Infinity }})
es el más rápido y confiable (al menos en la versión de MongoDB que probé).EDITAR: ¡Esto ya no funciona en MongoDB v3.6! Vea los comentarios en esta publicación para una posible solución.
Preparar
Inserté 1k documentos sin un campo de lista, 1k documentos con una lista vacía y 5 documentos con una lista no vacía.
Reconozco que esto no es una escala suficiente para tomar el rendimiento tan en serio como lo estoy en las pruebas a continuación, pero es suficiente para presentar la exactitud de varias consultas y el comportamiento de los planes de consulta elegidos.
Pruebas
db.doc.find({'nums': {'$exists': true}})
devuelve resultados incorrectos (para lo que estamos tratando de lograr).-
db.doc.find({'nums.0': {'$exists': true}})
devuelve resultados correctos, pero también es lento con un análisis de recopilación completo (COLLSCAN
etapa de aviso en la explicación).-
db.doc.find({'nums': { $exists: true, $gt: { '$size': 0 }}})
devuelve resultados incorrectos. Eso se debe a un escaneo de índice no válido que no avanza documentos. Es probable que sea precisa pero lenta sin el índice.-
db.doc.find({'nums': { $exists: true, $not: { '$size': 0 }}})
devuelve resultados correctos, pero el rendimiento es malo. Técnicamente realiza un escaneo de índice, pero luego avanza todos los documentos y luego tiene que filtrarlos).-
db.doc.find({'nums': { $exists: true, $ne: [] }})
devuelve resultados correctos y es un poco más rápido, pero el rendimiento aún no es el ideal. Utiliza IXSCAN que solo avanza documentos con un campo de lista existente, pero luego tiene que filtrar las listas vacías una por una.-
db.doc.find({'nums': { $gt: [] }})
ES PELIGROSO PORQUE DEPENDER DEL ÍNDICE UTILIZADO PUEDE DAR RESULTADOS INESPERADOS. Eso se debe a un escaneo de índice no válido que no avanza documentos.-
db.doc.find({'nums.0’: { $gt: -Infinity }})
devuelve resultados correctos, pero tiene un mal rendimiento (utiliza una exploración de recopilación completa).-
db.doc.find({'nums': { $gt: -Infinity }})
¡Sorprendentemente, esto funciona muy bien! Da los resultados correctos y es rápido, avanzando 5 documentos desde la fase de exploración del índice.fuente
seen_events
matriz de cadenas, que también está indexada.{ $gt: -Infinity }
Al buscar con , inmediatamente recibo 0 documentos. Con el uso{ $exists: true, $ne: [] }
obtengo los documentos de 1,2 m más probables, y se pierde mucho tiempo en la etapa FETCH: gist.github.com/N-Coder/b9e89a925e895c605d84bfeed648d82cdb.test_collection.find({"seen_events.0": {$exists: true}})
es malo porque usa un escaneo de colección. 2.db.test_collection.find({seen_events: {$exists: true, $ne: []}})
es . mala porque su IXSCAN coincide con todos los documentos y luego el filtrado se realiza en la fase lenta FETCH 3. lo mismo sucede condb.test_collection.find({seen_events: {$exists: true, $not: {$size: 0}}})
4. todos los demás consultas devuelven resultados no válidos..seen_events
contienen cadenas, puede utilizar la siguiente:db.test_collection.find({seen_events: {$gt: ''}}).count()
. Para confirmar que funciona bien, echa un vistazodb.test_collection.find({seen_events: {$gt: ''}}).explain(true).executionStats
. Probablemente pueda exigir que los eventos vistos sean cadenas a través de la validación de esquema: docs.mongodb.com/manual/core/schema-validationComenzando con la versión 2.6, otra forma de hacerlo es comparar el campo con una matriz vacía:
Probándolo en el shell:
Por lo tanto, incluye correctamente los documentos donde
pictures
tiene al menos un elemento de matriz, y excluye los documentos dondepictures
es una matriz vacía, no una matriz, o falta.fuente
db.ME.createIndex({ pictures: 1 })
y luegodb.ME.find({pictures: {$gt: []}})
devolverá cero resultados, al menos en MongoDB v3.0.14Puede usar cualquiera de los siguientes para lograr esto.
Ambos también se encargan de no devolver un resultado para los objetos que no tienen la clave solicitada:
fuente
Recupere todos y solo los documentos donde 'imágenes' es una matriz y no está vacía
Si usa una versión de MongoDb anterior a 3.2 , use en
$type: 4
lugar de$type: 'array'
. Tenga en cuenta que esta solución ni siquiera usa $ size , por lo que no hay problemas con los índices ("Las consultas no pueden usar índices para la porción $ size de una consulta")Otras soluciones, incluidas estas (respuesta aceptada):
están mal , ya que regresan documentos, incluso si, por ejemplo, 'imágenes' es
null
,undefined
, 0, etc.fuente
Utilice el
$elemMatch
operador: de acuerdo con la documentación$elemMatches
se asegura de que el valor sea una matriz y que no esté vacío. Entonces la consulta sería algo así comoME.find({ pictures: { $elemMatch: {$exists: true }}})
PD Una variante de este código se encuentra en el curso M121 de la Universidad MongoDB.
fuente
También puede usar el método auxiliar Existe sobre el operador Mongo $ existe
fuente
use $ where y pase this.field_name.length que devuelve el tamaño del campo de matriz y verifíquelo comparando con el número. si alguna matriz tiene un valor que el tamaño de la matriz debe ser al menos 1. entonces todos los campos de la matriz tienen una longitud de más de uno, significa que tiene algunos datos en esa matriz
fuente
Tan simple como eso, esto funcionó para mí.
fuente