mongodb - mongoose tutorial español
Encuentra registros de MongoDB donde el campo de matriz no está vacío (10)
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 sobre esto. He leído en la opción $ where, pero me preguntaba qué tan lento es para las funciones nativas, y si hay una solución mejor.
Y aun así, eso no funciona:
ME.find({$where: ''this.pictures.length > 0''}).sort(''-created'').limit(10).execFind()
No devuelve nada. Dejando esto, las this.pictures
sin el bit de longitud funcionan, pero luego también devuelve registros vacíos, por supuesto.
Recupere todos y solo los documentos donde ''imágenes'' es una matriz y no está vacío
ME.find({pictures: {$type: ''array'', $ne: []}})
Si usa una versión de MongoDb anterior a 3.2 , use $type: 4
lugar de $type: ''array''
. Tenga en cuenta que esta solución ni siquiera usa $size , por lo que no hay problema con los índices ("Las consultas no pueden usar índices para la porción de $ tamaño de una consulta")
Otras soluciones, incluyendo estas (respuesta aceptada):
ME.find ({fotos: {$ existe: verdadero, $ no: {$ tamaño: 0}}}); ME.find ({fotos: {$ existe: verdadero, $ ne: []}})
están equivocados porque devuelven documentos incluso si, por ejemplo, ''imágenes'' es null
, undefined
, 0, etc.
Comenzando con la versión 2.6, otra forma de hacer esto es comparar el campo con una matriz vacía:
ME.find({pictures: {$gt: []}})
Probando en la cáscara:
> db.ME.insert([
{pictures: [1,2,3]},
{pictures: []},
{pictures: ['''']},
{pictures: [0]},
{pictures: 1},
{foobar: 1}
])
> db.ME.find({pictures: {$gt: []}})
{ "_id": ObjectId("54d4d9ff96340090b6c1c4a7"), "pictures": [ 1, 2, 3 ] }
{ "_id": ObjectId("54d4d9ff96340090b6c1c4a9"), "pictures": [ "" ] }
{ "_id": ObjectId("54d4d9ff96340090b6c1c4aa"), "pictures": [ 0 ] }
Por lo tanto, incluye correctamente los documentos donde las pictures
tienen al menos un elemento de matriz, y excluye los documentos donde las pictures
son una matriz vacía, no una matriz o faltan.
Después de mirar un poco más, especialmente en los documentos mongodb, y confundir los bits juntos, esta fue la respuesta:
ME.find({pictures: {$exists: true, $not: {$size: 0}}})
Esto también podría funcionar para usted:
ME.find({''pictures.0'': {$exists: true}});
Puede utilizar cualquiera de los siguientes para lograr esto.
Ambos también se encargan de no devolver un resultado a los objetos que no tienen la clave solicitada:
db.video.find({pictures: {$exists: true, $gt: {$size: 0}}})
db.video.find({comments: {$exists: true, $not: {$size: 0}}})
Se preocupa por dos cosas al momento de la consulta: 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 MongoDB que probé).
EDIT: ¡Esto ya no funciona en MongoDB v3.6! Vea los comentarios en esta publicación para una solución potencial.
Preparar
Inserté 1k documentos con un campo de lista, 1k documentos con una lista vacía y 5 documentos con una lista no vacía.
for (var i = 0; i < 1000; i++) { db.doc.insert({}); }
for (var i = 0; i < 1000; i++) { db.doc.insert({ nums: [] }); }
for (var i = 0; i < 5; i++) { db.doc.insert({ nums: [1, 2, 3] }); }
db.doc.createIndex({ nums: 1 });
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 corrección 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).
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': {''$exists'': true}}).count()
1005
-
db.doc.find({''nums.0'': {''$exists'': true}})
devuelve los resultados correctos, pero también es lento al usar una exploración de colección completa (observe la etapa COLLSCAN
en la explicación).
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums.0'': {''$exists'': true}}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums.0'': {''$exists'': true}}).explain()
{
"queryPlanner": {
"plannerVersion": 1,
"namespace": "test.doc",
"indexFilterSet": false,
"parsedQuery": {
"nums.0": {
"$exists": true
}
},
"winningPlan": {
"stage": "COLLSCAN",
"filter": {
"nums.0": {
"$exists": true
}
},
"direction": "forward"
},
"rejectedPlans": [ ]
},
"serverInfo": {
"host": "MacBook-Pro",
"port": 27017,
"version": "3.0.14",
"gitVersion": "08352afcca24bfc145240a0fac9d28b978ab77f3"
},
"ok": 1
}
-
db.doc.find({''nums'': { $exists: true, $gt: { ''$size'': 0 }}})
devuelve resultados incorrectos. Esto se debe a que un escaneo de índice no válido avanza sin documentos. Es probable que sea preciso pero lento sin el índice.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $gt: { ''$size'': 0 }}}).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $gt: { ''$size'': 0 }}}).explain(''executionStats'').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 2,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"nums": {
"$gt": {
"$size": 0
}
}
},
{
"nums": {
"$exists": true
}
}
]
},
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 0,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"({ $size: 0.0 }, [])"
]
},
"keysExamined": 0,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({''nums'': { $exists: true, $not: { ''$size'': 0 }}})
devuelve resultados correctos, pero el rendimiento es malo. Técnicamente realiza una exploración de índice, pero aún así avanza todos los documentos y luego tiene que filtrarlos.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $not: { ''$size'': 0 }}}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $not: { ''$size'': 0 }}}).explain(''executionStats'').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2016,
"advanced": 5,
"needTime": 2010,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"nums": {
"$exists": true
}
},
{
"$not": {
"nums": {
"$size": 0
}
}
}
]
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2016,
"advanced": 5,
"needTime": 2010,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 2005,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 2005,
"executionTimeMillisEstimate": 0,
"works": 2015,
"advanced": 2005,
"needTime": 10,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"[MinKey, MaxKey]"
]
},
"keysExamined": 2015,
"dupsTested": 2015,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
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 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.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $ne: [] }}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $exists: true, $ne: [] }}).explain(''executionStats'').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 1018,
"advanced": 5,
"needTime": 1011,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"$not": {
"nums": {
"$eq": [ ]
}
}
},
{
"nums": {
"$exists": true
}
}
]
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 1017,
"advanced": 5,
"needTime": 1011,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 1005,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 1005,
"executionTimeMillisEstimate": 0,
"works": 1016,
"advanced": 1005,
"needTime": 11,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"[MinKey, undefined)",
"(undefined, [])",
"([], MaxKey]"
]
},
"keysExamined": 1016,
"dupsTested": 1015,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({''nums'': { $gt: [] }})
ES PELIGROSO PORQUE DEPENDER DEL ÍNDICE USADO PUEDE DAR RESULTADOS INESPERADOS. Esto se debe a una exploración de índice no válida que no avanza ningún documento.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $gt: [] }}).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $gt: [] }}).hint({ nums: 1 }).count()
0
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $gt: [] }}).hint({ _id: 1 }).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $gt: [] }}).explain(''executionStats'').executionStats.executionStages
{
"stage": "KEEP_MUTATIONS",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"inputStage": {
"stage": "FETCH",
"filter": {
"nums": {
"$gt": [ ]
}
},
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 0,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 0,
"executionTimeMillisEstimate": 0,
"works": 1,
"advanced": 0,
"needTime": 0,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"([], BinData(0, ))"
]
},
"keysExamined": 0,
"dupsTested": 0,
"dupsDropped": 0,
"seenInvalidated": 0,
"matchTested": 0
}
}
}
-
db.doc.find({''nums.0'': { $gt: -Infinity }})
devuelve los resultados correctos, pero tiene un mal rendimiento (utiliza un análisis de colección completa).
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums.0'': { $gt: -Infinity }}).count()
5
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums.0'': { $gt: -Infinity }}).explain(''executionStats'').executionStats.executionStages
{
"stage": "COLLSCAN",
"filter": {
"nums.0": {
"$gt": -Infinity
}
},
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 2007,
"advanced": 5,
"needTime": 2001,
"needFetch": 0,
"saveState": 15,
"restoreState": 15,
"isEOF": 1,
"invalidates": 0,
"direction": "forward",
"docsExamined": 2005
}
-
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.
MacBook-Pro(mongod-3.0.14) test> db.doc.find({''nums'': { $gt: -Infinity }}).explain(''executionStats'').executionStats.executionStages
{
"stage": "FETCH",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 16,
"advanced": 5,
"needTime": 10,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"docsExamined": 5,
"alreadyHasObj": 0,
"inputStage": {
"stage": "IXSCAN",
"nReturned": 5,
"executionTimeMillisEstimate": 0,
"works": 15,
"advanced": 5,
"needTime": 10,
"needFetch": 0,
"saveState": 0,
"restoreState": 0,
"isEOF": 1,
"invalidates": 0,
"keyPattern": {
"nums": 1
},
"indexName": "nums_1",
"isMultiKey": true,
"direction": "forward",
"indexBounds": {
"nums": [
"(-inf.0, inf.0]"
]
},
"keysExamined": 15,
"dupsTested": 15,
"dupsDropped": 10,
"seenInvalidated": 0,
"matchTested": 0
}
}
Si también tiene documentos que no tienen la clave, puede usar:
ME.find({ pictures: { $exists: true, $not: {$size: 0} } })
MongoDB no usa índices si se trata de $ size, por lo que aquí hay una mejor solución:
ME.find({ pictures: { $exists: true, $ne: [] } })
Desde la versión MongoDB 2.6, puede comparar con el operador $gt
pero podría llevar a resultados inesperados (puede encontrar una explicación detallada en esta respuesta ):
ME.find({ pictures: { $gt: [] } })
También puede usar el método de ayuda Exists sobre el operador Mongo $ existe
ME.find()
.exists(''pictures'')
.where(''pictures'').ne([])
.sort(''-created'')
.limit(10)
.exec(function(err, results){
...
});
ME.find({pictures: {$exists: true}})
Tan simple como eso, esto funcionó para mí.
{ $where: "this.pictures.length > 1" }
use $ where y pase the.field_name.length que devuelve el tamaño del campo de la matriz y verifíquelo comparando con el número. si cualquier matriz tiene un valor que no sea el tamaño de la matriz debe ser al menos 1. para que todo el campo de la matriz tenga una longitud mayor que uno, significa que tiene algunos datos en esa matriz