Para este tutorial, usaremos el official dummy dataset
, que contiene numerosos documentos de restaurantes de todo el área de Nueva York.
Aquí hay un ejemplo de la estructura básica del documento en esta colección, usando .findOne()
método:
> db.restaurants.findOne()
{
"_id" : ObjectId("56c651e7d84ccfde319961af"),
"address" : {
"building" : "469",
"coord" : [
-73.961704,
40.662942
],
"street" : "Flatbush Avenue",
"zipcode" : "11225"
},
"borough" : "Brooklyn",
"cuisine" : "Hamburgers",
"grades" : [
{
"date" : ISODate("2014-12-30T00:00:00Z"),
"grade" : "A",
"score" : 8
},
{
"date" : ISODate("2014-07-01T00:00:00Z"),
"grade" : "B",
"score" : 23
},
{
"date" : ISODate("2013-04-30T00:00:00Z"),
"grade" : "A",
"score" : 12
},
{
"date" : ISODate("2012-05-08T00:00:00Z"),
"grade" : "A",
"score" : 12
}
],
"name" : "Wendy'S",
"restaurant_id" : "30112340"
}
El poder de encontrar
La pieza más importante del rompecabezas al buscar dentro de una colección de MongoDB es el simple pero flexible db.collection.find()
método.
Con .find()
, puede consultar fácilmente una colección de documentos, pasando algunos parámetros simples y devolver un cursor
. Un cursor
es simplemente un conjunto de resultados y se puede iterar para manipular o hacer uso de los documentos a los que apunta el cursor
.
Como un ejemplo simple de .find()
en acción, intentaremos encontrar todos los restaurantes de nuestra colección que sirvan Hamburgers
como su cuisine
:
>db.restaurants.find( { cuisine: "Hamburgers" } )
{ "_id" : ObjectId("56c651e7d84ccfde319961af"), "address" : { "building" : "469", "coord" : [ -73.961704, 40.662942 ], "street" : "Flatbush Avenue", "zipcode" : "11225" }, "borough" : "Brooklyn", "cuisine" : "Hamburgers", "grades" : [ { "date" : ISODate("2014-12-30T00:00:00Z"), "grade" : "A", "score" : 8 }, { "date" : ISODate("2014-07-01T00:00:00Z"), "grade" : "B", "score" : 23 }, { "date" : ISODate("2013-04-30T00:00:00Z"), "grade" : "A", "score" : 12 }, { "date" : ISODate("2012-05-08T00:00:00Z"), "grade" : "A", "score" : 12 } ], "name" : "Wendy'S", "restaurant_id" : "30112340" }
...
El conjunto de resultados es bastante grande, por lo que una mejor medida para nuestros ejemplos de prueba sería encadenar .count()
método en .find()
para ver simplemente cuántos documentos coincidieron con nuestra consulta:
> db.restaurants.find( { cuisine: "Hamburgers" } ).count()
433
¡Son muchas hamburguesas!
Buscar similitudes de palabras usando Regex
Ahora que estamos usando .find()
para consultar nuestra colección, podemos modificar nuestra sintaxis ligeramente y comenzar a buscar coincidencias basadas en una palabra o frase que puede ser un parcial coincidencia dentro de un campo dado, similar a LIKE
operador para motores SQL.
El truco es utilizar regular expressions
(o regex
para abreviar), que es básicamente una cadena de texto que define un patrón de búsqueda. Hay una serie de regex
motores que están escritos en una sintaxis ligeramente diferente, pero los fundamentos son básicamente los mismos, y en este caso, MongoDB usa el Perl Regex (PCRE)
motor.
En el nivel más básico, una regex
expresión es una cadena (serie de caracteres) encerrada en ambos lados por una sola barra (/
).
Por ejemplo, si queremos usar regex
para realizar la misma consulta anterior y averiguar cuántos restaurantes sirven Hamburgers
, podemos reemplazar nuestra cadena "Hamburgers"
con /Hamburgers/
en cambio:
> db.restaurants.find( { cuisine: /Hamburgers/ } ).count()
433
Los observadores entusiastas pueden reconocer que efectivamente no hemos cambiado nada sobre la consulta real que estamos realizando; simplemente estamos buscando todos los documentos donde la cuisine
el campo es igual a la cadena "Hamburgers"
.
Dicho esto, simplemente usando regex
en lugar de una "cadena entrecomillada" normal, podemos comenzar a buscar coincidencias parciales de palabra/frase en su lugar.
Por ejemplo, echemos un vistazo al borough
campo para tener una mejor idea de cómo funciona esto. Primero notaremos que hay seis condados en total dentro de nuestra colección:
> db.restaurants.distinct('borough')
[
"Brooklyn",
"Bronx",
"Manhattan",
"Queens",
"Staten Island",
"Missing"
]
Ahora usemos regex
para averiguar cuántos restaurantes hay en el Bronx
municipio:
> db.restaurants.find( { borough: /Bronx/ } ).count()
2338
Pero imagina que queremos encontrar el número de restaurantes donde borough
empieza con los tres primeros caracteres "Bro"
. Modificaríamos nuestra regex
muy levemente, así:
> db.restaurants.find( { borough: /^Bro/ } ).count()
8424
Estamos viendo más de 6000 documentos adicionales en este conjunto de resultados, lo que tiene sentido porque no solo estamos obteniendo resultados donde el borough
es "Bronx"
, pero también todo para "Brooklyn"
también.
El carácter de intercalación (^
) especifica la ubicación en nuestra cadena que debería ser el comienzo , por lo que si tuviéramos un documento en el que esas tres letras estuvieran en medio del campo, no obtendríamos una coincidencia.
Como otro ejemplo rápido, busquemos en cualquier lugar en el campo para los caracteres "at"
, que debería darnos resultados tanto para "Manhattan"
y "Staten Island"
:
> db.restaurants.find( { borough: /Manhattan/ } ).count()
10259
> db.restaurants.find( { borough: /Staten Island/ } ).count()
969
> db.restaurants.find( { borough: /AT/i } ).count()
11228
Efectivamente, nuestra consulta final ha combinado los dos conjuntos de resultados en uno.
Puede notar que aunque nuestros personajes "AT"
están en mayúsculas en nuestro regex
cadena, pero son minúsculas en los registros de documentos reales, todavía devolvimos resultados. Esto se debe a que también agregamos el i
especial indicador que sigue a nuestra barra inclinada de cierre de expresiones regulares (/
). Esto informa a la regex
motor en el que queremos que la búsqueda sea case insensitive
, coincidiendo independientemente de mayúsculas o minúsculas.