Búsquedas en arrays en MongoDB

Tutorial de MongoDB con JavaEste es el quinto artículo correspondiente a las operaciones CRUD en MongoDB (Create, Read, Update, Delete). En el arterior artículo se realizó una introducción a las expresiones regulares en MongoDB y ahora se a va a continuar viendo cómo realizar búsquedas en arrays en MongoDB (arrays contenidos en los documentos).

Crear documentos con arrays en MongoDB

Para comenzar se van a insertar varios documentos JSON con un campo de tipo array, denominado “favorites”, que contendrá varios valores:

db.accounts.insert({ name: "Jose David", favorites: ["peanuts", "beer", "pretzels"] })
db.accounts.insert({ name: "George", favorites: ["pizza", "beer", "pretzels"] })

Para ver estos documentos de una forma más legible se van a mostrar los documentos anteriormente insertando usando el método pretty que como recordarán muestra los documentos en formato indentado:

> db.accounts.find().pretty()
{
	"_id" : ObjectId("513b222d1042e447a6c00ed1"),
	"name" : "Jose David",
	"favorites" : [
		"peanuts",
		"beer",
		"pretzels"
	]
}
{
	"_id" : ObjectId("513b22841042e447a6c00ed2"),
	"name" : "George",
	"favorites" : [
		"pizza",
		"beer",
		"pretzels"
	]
}

Se puede ver que los campos de tipo array se muestran con los distintos valores que contienen dentro de corchetes de tipo [].

Búsqueda en arrays en MongoDB

A continuación, se va ver que las consultas en MongoDB son polifórmicas con respecto a los arrays, es decir, se puede buscar por clave del mismo modo que si de una valor cualquiera se tratase como por ejemplo cadenas de caracteres o valores numéricos según sea el caso.

Por ejemplo, para encontrar los documentos que contengan la palabra “beer” dentro del array “favorites” se ejecuta el siguiente comando en la shell de MongoDB:

> db.accounts.find({ favorites: "beer"})
{ "_id" : ObjectId("513b222d1042e447a6c00ed1"), "name" : "Jose David", "favorites" : [ "peanuts", "beer", "pretzels" ] }
{ "_id" : ObjectId("513b22841042e447a6c00ed2"), "name" : "George", "favorites" : [ "pizza", "beer", "pretzels" ] }

Para que quede más claro el concepto de polimorfismo se añade otro documento con la clave “favorites” y valor “beer” como string (no array de strings) y se realiza una búsqueda sobre este valor:

> db.accounts.insert({ name: "Peter", favorites: "beer" })
> db.accounts.find({ favorites: "beer"})
{ "_id" : ObjectId("513b222d1042e447a6c00ed1"), "name" : "Jose David", "favorites" : [ "peanuts", "beer", "pretzels" ] }
{ "_id" : ObjectId("513b22841042e447a6c00ed2"), "name" : "George", "favorites" : [ "pizza", "beer", "pretzels" ] }
{ "_id" : ObjectId("513b256a1042e447a6c00ed3"), "name" : "Peter", "favorites" : "beer" }

Vemos como aparecen todas las coincidencias estén dentro de un array o simplemente sea una cadena de caracteres.

Ahora se va a buscar por el valor “pizza” de modo que sólo aparecerá “George” como resultado de la búsqueda:

> db.accounts.find({ favorites: "pizza"}).pretty()
{
	"_id" : ObjectId("513b22841042e447a6c00ed2"),
	"name" : "George",
	"favorites" : [
		"pizza",
		"beer",
		"pretzels"
	]
}

En el caso de estas búsquedas, MongoDB solamente busca en el “top level” del array ya que aún no permite búsquedas recursivas dentro de arrays de varios niveles (arrays de arrays o arrays de documentos que contengan arrays por ejemplo).

Además, se puede usar y complementar estas búsqueda junto con con otros criterios como por ejemplo ordenaciones, comparaciones, etc…

> db.accounts.find({ favorites: "beer", name : { $gte: "J"} }).pretty()
{
	"_id" : ObjectId("513b222d1042e447a6c00ed1"),
	"name" : "Jose David",
	"favorites" : [
		"peanuts",
		"beer",
		"pretzels"
	]
}

Búsqueda sólo dentro arrays en MongoDB

Ahora vamos a ver los distintos operadores que brinda MongoDB para buscar específicamente dentro del contenido de los arrays.

$all: Todos los valores deben existir

El operador $all encuentra todos los documentos que contengan todos los valores indicados dentro del array, eso si, estos pueden aparecer en cualquier orden.

Primeramente, se añade un nuevo documento con los valores anteriores y en distinto orden a como ya se tenia en otros documentos:

> db.accounts.insert({ name: "Will", favorites: ["pizza", "pretzels", "beer"] })

Y al realizar la búsqueda de documentos que contengan “beer” y “pizza” dentro del array “favorites” se puede ver como son encontrados aunque estén en distinto orden al especificado:

  db.accounts.find( { favorites: { $all: ["beer", "pizza"] }}).pretty()
{
	"_id" : ObjectId("513b22841042e447a6c00ed2"),
	"name" : "George",
	"favorites" : [
		"pizza",
		"beer",
		"pretzels"
	]
}
{
	"_id" : ObjectId("513b27231042e447a6c00ed4"),
	"name" : "George",
	"favorites" : [
		"pizza",
		"pretzels",
		"beer"
	]
}
{
	"_id" : ObjectId("513b27b71042e447a6c00ed5"),
	"name" : "Will",
	"favorites" : [
		"pizza",
		"pretzels",
		"beer"
	]
}

$in: Cualquier valor puede existir

El operador $in, por contra, toma una lista de posibles valores que puede contener un determinado campo, sea del tipo array o no, y encuentra todos los documentos que contengan alguna coincidencia (o todas), es decir, con que sólo uno de los valores exista se da el documento como resultado de la búsqueda:

db.accounts.find( { name: { $in: ["Will", "Jose David"] }}).pretty()
{
	"_id" : ObjectId("513b222d1042e447a6c00ed1"),
	"name" : "Jose David",
	"favorites" : [
		"peanuts",
		"beer",
		"pretzels"
	]
}
{
	"_id" : ObjectId("513b27b71042e447a6c00ed5"),
	"name" : "Will",
	"favorites" : [
		"pizza",
		"pretzels",
		"beer"
	]
}

Del mismo modo ocurre si estos valores se encuentran dentro de un array. Aunque sólo haya una coincidencia se obtiene el documentos:

db.accounts.find( { favorites: { $in: ["pizza", "peanuts"] }}).pretty()
{
	"_id" : ObjectId("513b222d1042e447a6c00ed1"),
	"name" : "Jose David",
	"favorites" : [
		"peanuts",
		"beer",
		"pretzels"
	]
}
{
	"_id" : ObjectId("513b22841042e447a6c00ed2"),
	"name" : "George",
	"favorites" : [
		"pizza",
		"beer",
		"pretzels"
	]
}
{
	"_id" : ObjectId("513b27b71042e447a6c00ed5"),
	"name" : "Will",
	"favorites" : [
		"pizza",
		"pretzels",
		"beer"
	]
}

Vemos como “Jose David” contiene sólo “peanuts” mientras los otros dos documentos contienen sólo “pizza”.

Estos operadores se pueden usar en común para crear consultas más restrictivas en documentos con varios campos arrays, por ejemplo:

db.users.find( { friends : { $all : [ "Joe" , "Bob" ] }, favorites : { $in : [ "running" , "pickles" ] } } )

Esta query encontraría todos los documentos que contengan los elementos “Joe” y “Bob”, en cualquier orden, dentro del array “friends” y con alguno de los dos valores (o ambos), “running” y “pickles”, dentro del array “favorites”.

Conclusión

Como se puede apreciar en estos ejemplos, la búsquedas en arrays en MongoDB es bastante sencilla ya que con prácticamente tres formas (búsqueda simple, all e in) se pueden realizar todas las combinaciones que se deseen.

No duden en dejar un comentario para cualquier duda o comentario y aprovecho para animaros en el seguimiento de este tutorial de MongoDB con Java ya que, para muchos, esta parte, que es puramente en la shell de MongoDB, puede resultar más aburrida y tediosa pero la considero fundamental para entender los conceptos correctamente y poder realizar posteriores operaciones desde Java.

Happy Minds!!!

Share on FacebookTweet about this on TwitterShare on LinkedInShare on RedditShare on Google+Digg thisShare on TumblrPin on PinterestBuffer this pagePrint this pageEmail this to someone