Consulta de documentos donde el tamaño del array es mayor que 1


Tengo una colección MongoDB con documentos en el siguiente formato:

{
  "_id" : ObjectId("4e8ae86d08101908e1000001"),
  "name" : ["Name"],
  "zipcode" : ["2223"]
}
{
  "_id" : ObjectId("4e8ae86d08101908e1000002"),
  "name" : ["Another ", "Name"],
  "zipcode" : ["2224"]
}

Actualmente puedo obtener documentos que coinciden con un tamaño de matriz específico:

db.accommodations.find({ name : { $size : 2 }})

Esto devuelve correctamente los documentos con 2 elementos en el array name. Sin embargo, no puedo hacer un comando $gt para devolver todos los documentos donde el campo name tiene un tamaño de matriz mayor que 2:

db.accommodations.find({ name : { $size: { $gt : 1 } }})

¿Cómo puedo seleccionar todos los documentos con una matriz name de un tamaño mayor que uno (preferiblemente sin tener que modificar la estructura de datos actual)?

Author: styvane, 2011-10-18

10 answers

Actualización:

Para versiones mongodb 2.2+ una forma más eficiente de hacer esto descrita por @JohnnyHK en otra respuesta .


1.Usando where donde

db.accommodations.find( { $where: "this.name.length > 1" } );

Pero...

Javascript se ejecuta más lentamente que los operadores nativos listados en esta página, pero es muy flexible. Consulte la página de procesamiento del lado del servidor para más información.

2.Crear extra campo NamesArrayLength, actualizarlo con la longitud de la matriz de nombres y luego usar en consultas:

db.accommodations.find({"NamesArrayLength": {$gt: 1} });

Será una mejor solución, y funcionará mucho más rápido (puede crear un índice en él).

 376
Author: Andrew Orsich,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:36

Hay una forma más eficiente de hacer esto en MongoDB 2.2+ ahora que puede usar índices de matriz numérica en claves de objeto de consulta.

// Find all docs that have at least a second name array element.
db.accommodations.find({'name.1': {$exists: true}})
 1051
Author: JohnnyHK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-12 21:18:18

Creo que esta es la consulta más rápida que responde a su pregunta, porque no utiliza una cláusula interpretada $where:

{$nor: [
    {name: {$exists: false}},
    {name: {$size: 0}},
    {name: {$size: 1}}
]}

Significa "todos los documentos excepto aquellos sin un nombre (ya sea un array inexistente o vacío) o con un solo nombre."

Prueba:

> db.test.save({})
> db.test.save({name: []})
> db.test.save({name: ['George']})
> db.test.save({name: ['George', 'Raymond']})
> db.test.save({name: ['George', 'Raymond', 'Richard']})
> db.test.save({name: ['George', 'Raymond', 'Richard', 'Martin']})
> db.test.find({$nor: [{name: {$exists: false}}, {name: {$size: 0}}, {name: {$size: 1}}]})
{ "_id" : ObjectId("511907e3fb13145a3d2e225b"), "name" : [ "George", "Raymond" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225c"), "name" : [ "George", "Raymond", "Richard" ] }
{ "_id" : ObjectId("511907e3fb13145a3d2e225d"), "name" : [ "George", "Raymond", "Richard", "Martin" ] }
>
 109
Author: Tobia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-11 15:08:03

También puedes usar aggregate:

db.accommodations.aggregate(
[
     {$project: {_id:1, name:1, zipcode:1, 
                 size_of_name: {$size: "$name"}
                }
     },
     {$match: {"size_of_name": {$gt: 1}}}
])

/ / agrega "size_of_name" al documento de tránsito y lo usa para filtrar el tamaño del nombre

 41
Author: one_cent_thought,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-23 19:00:06

Nada de lo anterior funcionó para mí. Este lo hizo así que lo estoy compartiendo:

db.collection.find( {arrayName : {$exists:true}, $where:'this.arrayName.length>1'} )
 30
Author: Zloy Smiertniy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-14 01:06:04

Intenta hacer algo como esto:

db.getCollection('collectionName').find({'ArrayName.1': {$exists: true}})

1 es el número, si desea obtener un registro mayor que 50, haga arrayName.50 Gracias.

 28
Author: Aman Goel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-19 06:37:16
db.accommodations.find({"name":{"$exists":true, "$ne":[], "$not":{"$size":1}}})
 16
Author: Yadvendar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-22 13:54:14

Encontré esta solución, para encontrar elementos con un campo de matriz mayor que cierta longitud

db.allusers.aggregate([
  {$match:{username:{$exists:true}}},
  {$project: { count: { $size:"$locations.lat" }}},
  {$match:{count:{$gt:20}}}
])

El primer agregado match match usa un argumento que es verdadero para todos los documentos. Si estuviera en blanco, obtendría

"errmsg" : "exception: The argument to $size must be an Array, but was of type: EOO"
 9
Author: Barrard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-06 01:46:59

Puede usar exp expr (3.6 mongo version operator ) para usar funciones de agregación en consultas regulares.

Comparar query operators vs aggregation comparison operators.

db.accommodations.find({$expr:{$gt:[{$size:"$name"}, 1]}})
 8
Author: Veeram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-23 21:13:50

Aunque todas las respuestas anteriores funcionan, lo que originalmente intentó hacer fue de la manera correcta, sin embargo, solo tiene la sintaxis al revés (cambiar "size size" y "gt gt")..

Correcto:

db.collection.find({items: {$gt: {$size: 1}}})

Incorrecto:

db.collection.find({items: {$size: {$gt: 1}}})
 -5
Author: Steffan Perry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-10 01:15:48