MongoDB: encuentra tus datos con consultas simples

A lo largo de varios artículos sobre MongoDB, hemos visto como insertar datos, modificarlos o como crear y gestionar índices. Pero todavía nos queda una de las partes más importantes: la consulta de datos.

Está claro que uno de los pilares en el uso de una base datos, es localizar la información. Las bases de datos relacionales de toda la vida, tienen un lenguaje propio para realizar consultas. Es el Structured Query Language, más conocido como SQL. Pero en MongoDB no tenemos la posibilidad de utilizar SQL. En este caso, y al igual que con los otros tipos de consultas, las búsquedas se realizarán con Javascript.

En este artículo, vamos a ver como podemos realizar consultas sencillas desde la shell de MongoDB.

Usando find

La función find nos permite buscar documentos en una colección. Si no le pasamos ningún parámetro, se buscarán todos los elementos en la colección.

Supongamos, por ejemplo, que tenemos una colección llamada genbetadev que tiene documentos como los siguientes:

    /* 0 */
    {
        "_id" : 1,
        "nombre" : "rubenfa",
        "publicados" : 12
    }
    
    /* 1 */
    {
        "_id" : 2,
        "nombre" : "Txema Rodríguez",
        "publicados" : 320
    }
    
    /* 2 */
    {
        "_id" : 3,
        "nombre" : "Cecilio Álvarez",
        "publicados" : 25
    }

Para buscar todos los documentos, tenemos que hacer algo similar a:

    db.genbetadev.find();

Aunque lo lógico sería pensar que MongoDB nos devolvería todos los resultados, esto no es así. Para evitar devolver demasiados documentos y sobrecargar el servidor, MongoDB utiliza los cursores.

Cursores

Un cursor es una conexión con el servidor que permanece abierta, y que permite iterar sobre los resultados de una consulta, de forma que estos se devuelvan poco a poco. Por defecto un cursor en la shell (si no se asigna a una variable), devuelve 20 elementos. Si nuestra intención fuera recorrer todos los resultados que nos devuelve un cursor, podríamos usar un script parecido a este:

    var miCursor = db.genbetadev.find();
    
    while (miCursor.hasNext()){
        printjson(miCursor.next());
    };  

Los cursores, también nos permiten otras opciones, como establecer un límite de resultados devueltos, o incluso saltarnos un número determinado de ellos. Por ejemplo:

    db.genbetadev.find().skip(2)
    { "_id" : 3, "nombre" : "Cecilio Álvarez", "publicados" : 25 }

Con skip estamos diciendo al cursor, que se salte un número de registros concreto, en este caso dos.

    db.genbetadev.find().limit(2);
    { "_id" : 1, "nombre" : "rubenfa", "publicados" : 12 }
    { "_id" : 2, "nombre" : "Txema Rodríguez", "publicados" : 320 }

Con limit, queremos que el cursor, devuelva solo el número de registros indicado. En este caso dos.

Ambos operadores se pueden concatenar, proporcionándonos una interesante opción para paginar resultados:

    db.genbetadev.find().limit(1).skip(2);
    { "_id" : 3, "nombre" : "Cecilio Álvarez", "publicados" : 25 }

Filtros

En los ejemplos anteriores hemos utilizado find sin ningún filtro. Pensando en SQL, podríamos decir que estamos haciendo una SELECT sin cláusula WHERE.

Para añadir un filtro, tendremos que pasar un documento JSON como parámetro de la consulta.

    db.genbetadev.find({"_id":2});
    { "_id" : 2, "nombre" : "Txema Rodríguez", "publicados" : 320 }

En este caso el filtro es bastante sencillo. Estamos buscando solo los documentos que tengan un campo *_id** igual a 2. En los filtros para realizar consultas podemos usar operadores, que nos permitirán mejorar los filtros. Los iremos viendo en posteriores artículos.

Proyecciones

Una proyección se utiliza para devolver un conjunto determinado de campos de un documento. En los ejemplos anteriores, estábamos devolviendo todos los campos de un documento, pero es posible que no necesitemos todos. Es decir, que en lugar de hacer un SELECT , realizaremos un SELECT nombrecampo. Las proyecciones se tienen que incorporar en el segundo parámetro del comando *find.

    db.genbetadev.find({},{"nombre":1});
    { "_id" : 1, "nombre" : "rubenfa" }
    { "_id" : 2, "nombre" : "Txema Rodríguez" }
    { "_id" : 3, "nombre" : "Cecilio Álvarez" }

En este caso estamos aplicando un filtro vacío (se devuelven todos los documentos), y estamos diciendo que solo queremos devolver el campo nombre. MongoDB, por defecto, nos devuelve también el _id. Para no mostrarlo deberemos especificar de forma explícita que no lo queremos. Se haría así:

    db.genbetadev.find({},{"nombre":1,"_id":0});
    { "nombre" : "rubenfa" }
    { "nombre" : "Txema Rodríguez" }
    { "nombre" : "Cecilio Álvarez" }

Por tanto, las proyecciones se realizan indicando el nombre del campo, añadiendo un 1 si queremos mostrarlo y un 0 si no queremos.

Usando findOne

Hay ocasiones en que solo necesitamos un documento, aun sabiendo que la consulta va a devolver más de uno. En estas ocasiones podemos utilizar findOne, que nos devuelve un solo documento.

    db.genbetadev.findOne();
    { "_id" : 1, "nombre" : "rubenfa", "publicados" : 12 }

El comando findOne no devuelve un cursor. En este caso devuelve un documento concreto, lo que nos da opciones interesantes. Por ejemplo la posibilidad de asignar el documento directamente a una variable para poder realizar operaciones sobre ella.

    function muchosOPocos(documento){
      if(documento.publicados > 20){
        print("muchos");
      }
      else
      {
        print("pocos");
      }
    };
    
    var miDocumento = db.genbetadev.findOne();
    muchosOPocos(miDocumento);
    
    pocos

Usando findAndModify

Y terminamos el repaso a los comandos de consulta con uno que tiene un comportamiento diferente. Muchas veces nos vemos en la necesidad de buscar un documento para modificar alguno de sus campos y luego devolverlo para procesarlo en la aplicación. Esto lo podemos hacer de forma atómica con findAndModify.

Este comando recibe los siguientes parámetros:

  • Query: Los criterios de búsqueda. El filtro que dice que documentos deben buscarse. Igual que en find y en findOne. Aunque la consulta devuelva varios documentos, solo se modificará uno de ellos
  • Sort: podemos especificar un orden para tener control sobre el documento que se modificará en caso de que se devuelvan varios resultados.
  • Remove: campo booleano. Este parámetro no es necesario si se añade el parámetro Update (ver siguiente punto). Si el valor es true, se borrará el documento encontrado.
  • Update: este parámetro no es necesario si se añade el parámetro Remove (ver punto anterior). En este campo deberemos introducir un JSON con la sentencia de actualización.
  • New: campo booleano. Si es true se devuelve el documento ya modificado, si es false se devuelve el original.
  • Fields: proyección con los datos que queremos devolver.
  • Upsert: si es true y la consulta no encuentra documentos, se creará un documento nuevo. En otro caso se actualizará el documento.

Así que con nuestros datos, podríamos ejecutar un comando similar a este:

    db.genbetadev.findAndModify({
      query:{"_id":1},
      sort: {},
      update: { "$inc":{"publicados":1}},
      new: false,
      fields: {},
      upsert:false
      });

    { "_id" : 1, "nombre" : "rubenfa", "publicados" : 12 }

En el ejemplo estamos buscando el documento con _id = 1, para incrementar el campo publicados en una unidad (usando el operador $inc). En este caso findAndModify nos ha devuelto el documento original sin modificar, ya que hemos establecido el parámetro new a false. Pero si hacemos una nueva consulta, veremos que el número de publicados se ha incrementado en uno.

     db.genbetadev.find({"_id":1});
    { "_id" : 1, "nombre" : "rubenfa", "publicados" : 13 }

Y con esto hemos repasado de manera sencilla la forma realizar consultas. Aunque aun nos quedan cosas por ver. ¿Cómo hacer consultas con OR? ¿Y si quiero que se devuelvan los documentos con un campo mayor que n? ¿Y si quiero buscar valores dentro de un array? Pues todas estas operaciones son también posibles y las veremos en próximos artículos.

Imagen | amortize

En GenbetaDev | MongoDB: la vida cambia, tus datos también. Actualiza subdocumentos y añade datos a un array, MongoDB: creación y utilización de índices

Ver todos los comentarios en https://www.genbeta.com

VER 0 Comentario

Portada de Genbeta