Balanceo de carga en Redis con Nginx

Vuelvo a la carga con un post de Arquitectura para compartir cómo usar Nginx (tanto la versión Open Source como la versión de pago – Nginx Plus) para balancear la carga entre varios servidores Redis.

Introducción a Nginx y Redis

Nginx es un servidor proxy HTTP inverso, un servidor proxy de correo y un servidor proxy TCP / UDP genérico. Productos similares serían HAProxy y Apache.

Redis es un almacén en memoria de estructuras de datos open-source, utilizado como base de datos, caché y broker de mensajes.

Solución al balanceo de carga

El balanceo de carga se refiere a la distribución del tráfico de red entre múltiples servidores backend. Estamos más acostumbrados a utilizar el módulo HTTP de Nginx utilizándolo de proxy o balancear la carga de tráfico HTTP. Desde hace algunas versiones Nginx admite el balanceo de carga de tráfico tanto TCP como UDP.

Para cambiar la configuración de Nginx debemos modificar el fichero o ficheros de configuración, en el caso de que tengamos varios que luego incluiremos con claúsulas “include“. El fichero de configuración principal por defecto de Nginx generalmente se encuentra en /etc/nginx/nginx.conf:

stream {
 server {
 listen 12345;

 #TCP traffic will be proxied to the "stream_backend" upstream group
 proxy_pass stream_backend;
 }

 server {
 listen 12346;

 #TCP traffic will be proxied a proxied server
 proxy_pass backend.example.com:12346;
 }

 server {
 listen 53 udp;

 #UDP traffic will be proxied to the "dns_servers" upstream group
 proxy_pass dns_servers;
 }
 

 upstream stream_backend {
 server 10.0.18.4:18840;
 server 10.0.18.5:18840;
 server 10.0.18.6:18840;
 }
 
 upstream dns_servers {
 server 10.0.18.4:18840;
 server 10.0.18.5:18840;
 server 10.0.18.6:18840;
 }
}
  1. Crearemos un bloque “stream {}” de primer nivel
  2. Definiremos uno o más bloques “server {}” para configurar cada servidor virtual dentro del bloque stream.
  3. Dentro de cada bloque server definiremos mediante la directiva “listen” el puerto en el que el servidor (nginx) escucha tráfico (si es tráfico udp lo especificamos).
  4. Incluiremos además dentro de “server” la directiva “proxy-pass” para definir el servidor o el grupo de upstreams en los cuales se redigirá el tráfico.
  5. Definimos uno o más bloques “upstream {}” de configuración dentro del bloque “stream” estableciendo un nombre a los mismos.
  6. Añadimos a los upstreams una directiva “server” por cada uno de los servidores Redis junto con su dirección IP y su puerto

Conclusión

Hasta aquí la configuración más básica, podemos especificar además el método de balanceo de carga (round-robin, least_conn, least_time, hash) así como parámetros específicos tanto para el número de conexiones máximo, el peso de cada servidor, etc. Al igual que el tráfico de Redis esta solución es aplicable a todo tráfico de red a través del protocolo TCP/UDP. Tienes más información aquí: tcp-load-balancing

 

 

 

Descubrimiento de Microservicios con Nginx y Consul

En una entrada previa ya traté el enfoque de Microservicios y cómo dividir en servicios de grado más fino, independientes, que exponen un API y que colaboran juntos a través de peticiones HTTP. En esta veremos una solución con Nginx y Consul para el descubrimiento dinámico de microservicios.

Una vez que tenemos unos cuantos microservicios, incluso varias instancias de cada uno para balancear la carga, nuestra atención pasa inevitablemente por conocer dónde están desplegados cada uno de ellos, ya que los mismos pueden “convivir” en el mismo servidor, en diferentes servidores de nuestra infraestructura, o en servicios cloud como el de Amazon. Necesitamos conocer si están o no en ejecución además de su IP y puerto.

La solución pasa por un mecanismo de autoregistro de los microservicios en el momento del despliegue en un catálogo de servicios en “runtime”, una forma de decir: “Estoy vivo y me puedes encontrar en esta IP y este puerto”. En el momento del “undeploy” debería desregistrarse del mismo.

Consul

Consul es un sistema distribuido open source creado por Hashicorp para el registro de servicios y la configuración de los mismos. Provee un API que permite a los servicios el registro/desregistro en su catálogo. Consul provee igualmente de un chequeo constante de la salud de los servicios, marcando aquéllos que no pasan el mismo. El cluster de Consul se compone de diferentes procesos agente que se encuentran ejecutándose en los mismos servidores en los que se localizan los servicios, de manera que cada servicio se registra en el agente Consul de su servidor. Estos procesos agente pueden ejecutarse en modo cliente o en modo Servidor. Se recomienda ejecutar entre 3 y 5 agentes en modo Servidor.

consul-arch-5d4e3623

Cualquier registro/desregistro en un nodo del cluster se propaga por el mismo. Todos los nodos del cluster conocen el catálogo de servicios (sus nombres, direcciones ip y puertos).

Una vez que tenemos un catálogo “runtime” de servicios necesitamos un proxy inverso como Apache, HAProxy o Nginx que enrute las peticiones y balancee la carga entre las distintas instancias de un servicio. Todas las peticiones llegarán a uno o más proxies y éste será el encargado del enrutamiento. El problema a resolver en este escenario es llegar a hacer dinámica la configuración de Nginx, o del proxy que se desee de los expuestos anteriormente.

La configuración de servicios se realiza en un fichero, por lo que si la misma se modifica (modificando el fichero), Nginx debería recargarse y leer la nueva. Pero, ¿quién se encarga de reescribir la configuración de Nginx cuando el catálogo de Consul recibe un alta o una baja de un servicio?

Consul-Template

Consul-Template es un proceso que se ejecuta en uno de los nodos del cluster de Consul (mismo servidor que uno de los agentes Consul) y es capaz de escribir en un fichero del File System los cambios en el catálogo de servicios a través de una plantilla. Esta plantilla la transforma en un fichero de configuración en disco y cuando finaliza puede ejecutar un comando del sistema, forzando a nginx a recargar la configuración.

$ consul-template \
  -consul my.consul.internal:6124 \
  -template "/tmp/nginx.ctmpl:/var/nginx/nginx.conf:service nginx restart"

Con el comando de arriba se ejecuta el proceso que estará ejecutándose en segundo plano consultando al agente Consul que indicamos en el parámetro -consul. El parámetro -template indica que la plantilla para el rendering del fichero se encuentra en /tmp/nginx.ctmpl y sobrescribe la configuración de nginx en /var/nginx/nginx.conf. Una vez sobreescrito el fichero se ejecuta el comando que recarga la configuración de Nginx, service nginx restart, en el ejemplo de arriba.

All together

En  el siguiente esquema observamos todos los componentes unidos y colaborando tal y cómo se ha expuesto más arriba.

registroServicios

Arquitecturas de este tipo son fáciles de implementar y distribuir incluso si nos vamos a una infraestructura basada en contenedores docker. El sistema es escalable y de alta disponibilidad con la inclusión de varios nodos con Nginx y Consul-Template.

Microservicios – Introducción: ¿Están las empresas preparadas?

Es difícil que no hayas escuchado antes el término Microservicio, e incluso puede ser que hayas entrado en esta página buscando información sobre ello. Se trata de un término muy en boga en la actualidad, aunque también escucharás hablar de “Arquitectura de microservicios” o de que una aplicación sigue dicha arquitectura.

Definición

Cuando hablamos de microservicios nos referimos a un enfoque orientado a sistemas distribuidos que promueven el uso de servicios de grado más fino, con sus propios ciclos de vida, que colaboran juntos a través de peticiones HTTP a sus API.

Debido a que los microservicios se modelan en torno a los dominios de negocio, se evitan los problemas de arquitecturas en capas y monolíticas tradicionales.

Además cada microservicio es independiente y su código debe ser desplegado sin afectar a los demás. Cada uno de ellos puede escribirse en el lenguaje de programación más adecuado, ya que sólo exportan la API.

Ventajas

Los microservicios por tanto son un nuevo enfoque de las aplicaciones tradicionales, en las cuales teníamos un servidor ejecutando el código de la aplicación en un archivo war. Cada vez que algún módulo / servicio sufría un cambio, debíamos subir a producción de nuevo todo el código, incluyendo los módulos no modificados. En el caso de que haya un módulo de la aplicación que se encuentre saturado de peticiones y queramos balancear la carga, es necesario replicar toda la aplicación en otro servidor.

Frente al enfoque tradicional y en vez de tener un único ejecutable, cada servicio se ejecuta en su propio proceso, comunicándose entre si mediante llamadas a sus respectivas API. Cada microservicio, por tanto se puede desplegar de forma autónoma, de manera que dicho despliegue no afecta a los demás microservicios. Son más fáciles de escalar ya que en vez de replicar toda la aplicación, lo haremos sólo de los microservicios con más carga.

microservicios-fowler

Otras ventajas de esta arquitectura es que se reduce el “Time to market” debido a que evita retrasos en la integración de la nueva funcionalidad en la aplicación monolítica. No hay unanimidad sobre esto, ya que diferentes autores indican que debido a la naturaleza distribuida de la aplicación el time to market será mayor. A continuación se enumeran las ventajas de este enfoque:

  • Los servicios son muy simples, enfocados en hacer una cosa y hacerla bien. Algunos autores aseguran que Microservicios es SOA bien hecho.
  • Cada servicio puede ser construido utilizando la mejor herramienta y la más apropiada para el trabajo que va a realizar.
  • Se trata de sistemas débilmente acoplados.
  • Múltiples desarrolladores y equipos pueden realizar entregas de manera independiente.
  •  Facilita la entrega continua, permitiendo lanzamientos frecuentes, manteniendo el resto del sistema disponible y estable.

Desventajas

Pero no todo son ventajas y un sistema basado en Microservicios posee una complejidad añadida:

  • Un gran número de microservicios son difíciles de orquestar.
  • Dificultad para gestionar y realizar test de las dependencias.
  • Aplicación no uniforme. Poder elegir entre diferentes tecnologías conlleva diseños de aplicación y arquitectura no uniformes, lo que puede incrementar el coste de mantenimiento a largo plazo.
  • Complejidad DevOps. Es necesario tener un equipo Dev Ops maduro para manejar la complejidad en mantener aplicaciones basadas en microservicios.
  • Incremento del uso de recursos. La inversión inicial para ejecutar estas aplicaciones es alto, debido a la ejecución independiente de cada componente en su propio proceso o contenedor de ejecución (más RAM y CPU).
  • Incremento de la comunicación por la red. Este sistema requiere conexiones confiables y rápidas.
  • Marshalling – Unmarshalling. Cuando un servicio requiere datos de otro, el llamante encapsula los datos en algún estándar desde su representación interna, mientras que el llamado realiza una la operación contraria para operar con dichos datos. Esto requiere más procesamiento en comparación con una arquitectura de aplicación convencional.
  • Seguridad en la red. La comunicación entre servicios necesita ser securizada para evitar brechas de seguridad. Debido a la composición de diferentes módulos “movibles”, estas aplicaciones son más vulnerables en cuanto a seguridad.
  • Testing. Incremento de la complejidad para realizar testing de estas aplicaciones en comparación con aplicaciones monolíticas.
  • Monitorización en producción. El coste de monitorizar esta aplicación es mayor y la no disponibilidad de las herramientas adecuadas es un tema a ser considerado.
  • Logs y trazas. nos encontramos con una fuente inagotable de logs generados por cada uno de los procesos, por los contenedores que ejecutan los microservicios y por el propio servidor físico o virtual.
  • Transaccionalidad en las operaciones. Los microservicios por naturaleza son “stateless, por lo que se ve la necesidad de una tercera capa de persistencia y gestión de la transaccionalidad.

implement-microservices

Conclusiones

Se trata de un enfoque que no es nuevo pero en el que muchas empresas están poniendo el foco debido a la complejidad a la que han llegado sus aplicaciones empresariales. La Arquitectura de microservicios no es para todo el mundo pero se adapta perfectamente a aplicaciones enterprise o proyectos que seguro van a escalar. La velocidad gana en el mercado y la idea de Microservicios es ganar en velocidad, pero también supone cambios en la empresa, empezando por integrar primero DevOps y herramientas de DevOps en la misma. ¿Están las empresas preparadas para dar el paso a Microservicios?

Controla la calidad del código con SonarQube

El software SonarQube, anteriormente llamado Sonar es la plataforma abierta más popular para gestionar la calidad del software.

Todos los implicados en el desarrollo de software estamos concienciados en que es indispensable construir buen código, aunque estarás de acuerdo conmigo en que no siempre se consigue. Errores en el software han provocado graves problemas, pérdidas millonarias, e incluso muerte de personas. Podéis leer los siguientes ejemplos: List of software bugs y Top 8 de errores informáticos más costosos de la historia.

Sonarqube nos ayuda en nuestra tarea. Es software libre y evalúa el código fuente usando diversas herramientas de análisis cómo Checkstyle, PMD o FindBugs. Este análisis se consolida en métricas que nos ayudarán a medir y mejorar la calidad de nuestro software. La plataforma cubre 7 ejes para realizar el análisis:

  • Reglas de codificación
  • Diseño y Arquitectura
  • Código duplicado
  • Complejidad del código
  • Pruebas unitarias
  • Errores potenciales
  • Comentarios en el código

sonar1

SonarQube es extensible mediante plugins, de manera que es posible analizar más de 20 lenguajes de programación, incluidos Java, C#, C/C++, PL/SQL, Cobol… Estos plugins permiten de igual manera añadir nuevos lenguajes e incorporar nuevas reglas o métricas avanzadas.

SonarQube es una aplicación basada en web, por lo que las reglas, alertas, configuraciones y demás se pueden configurar online. Además, su base de datos embebida puede ampliarse y configurar una externa como MySQL, Oracle, PostgreSQL, etc. No sólo permite combinar métricas, sino también comparar con las medidas históricas. Otra característica primordial es que puede integrarse en servidores de integración continua.

Instalación

La plataforma está compuesta de tres elementos:

  • Una base de datos para almacenar la configuración de la instancia y los resultados del análisis de proyectos, vistas, etc.
  • Un servidor web para visualizar los análisis y configurar la instancia.
  • Uno o más analizadores para analizar proyectos.

Como hemos dicho SonarQube se distribuye con una base de datos embebida, así que para comenzar a trabajar tan solo tenemos que descargar la última versión del servidor y descomprimirla en un directorio.

Una vez completada, ejecutamos el proceso del servidor ejecutando:

  • Linux / Mac: <directorio_instalación>/bin/<tu_sistema_operativo>/sonar.sh
  • Windows: <directorio_instalación>/bin/windows-x86-XX/StartSonar.bat

Por defecto está configurado en el puerto 9000 (http://localhost:9000), pero es posible modificarlo en el fichero de configuración sonar.properties que se encuentra en el directorio conf del directorio de instalación.

Analizadores

Están disponibles los siguientes analizadores:

  • SonarQube runner: recomendado para proyectos sin Maven
  • Maven: recomendado para proyectos “mavenizados
  • SonarQube Ant Task: Para integrar proyectos con Ant
  • Gradle: Para integrar proyectos construidos con Gradle
  • Continuous integration: Plugins para Jenkins, Hudson, Bamboo o AnthillPro.

SonarQube runner es un analizador manual, de manera que ejecutaremos el programa cada vez que queramos realizar un análisis de código. Mediante un fichero de configuración indicaremos tanto la carpeta dónde se encuentra el código fuente como la versión de análisis. Los demás analizadores son programados, por lo que el analizador se ejecutará cuando sea necesario, bien sea una vez al día, cada vez que se construye el proyecto, cada vez que se sube al control de fuentes, todo a la vez, etc.

Métricas

El cuadro de mando de SonarQube es una interfaz web donde podemos ver los resultados del análisis con los puntos débiles a mejorar. Puedes ver un cuadro de mando SonarQube en nemo.sonarqube.org. Las métricas que puedes consultar las configuramos según nuestras necesidades pero por defecto se muestran las siguientes:

  1. Complejidad. Complejidad ciclomática. Cada vez que sonarqube encuentra una sentencia“if”,”for”,”while”,”case”,”catch”, “throw”,”return” (sin ser la última sentencia de un método), “&&”, “||”, “?”, “else”, se aumenta el contador global de complejidad ciclomática en 1. También se aumenta en 1 el contador por la cabecera del método. Otros valores para la complejidad son:
    • Complejidad/método. Media de la complejidad por cada método. debería sobrepasar el valor de 30.
    • Complejidad/clase. Media de la complejidad de todas las clases. Un valor muy elevado de complejidad ciclomática por clase, nos indica síntomas de un mal diseño.
    • Complejidad/fichero. Media de la complejidad por fichero.
  2. Código duplicado. Cuanto mayor sea la complejidad ciclomática y la duplicidad de código, más difícil será mantener el software, por tanto se trata de una métrica básica. Por defecto se considera una duplicidad de código cuando 10 líneas sucesivas de código se encuentran duplicadas. Sonarqube nos muestra las siguientes métricas para esta categoría.
    • Líneas duplicadas.
    • Bloques duplicados.
    • Archivos duplicados.
    • Número de líneas duplicadas (%). (Número de líneas duplicadas/Número total de líneas) *100
  3. Comentarios. La información mostrada para esta categoría:
    • Líneas comentadas. Número de líneas con comentario.
    • Comentarios (%). Si el valor es un 50% indica que la mitad del fichero es código y la mitad comentarios, si es un 100% indica que son todo comentarios.
  4. Test. Muestra el tanto por ciento de cobertura de pruebas unitarias del proyecto, y en caso de que las haya, cuántas de ellas ha pasado nuestro software. Si bien para otras métricas únicamente es necesario analizar el código fuente, para obtener resultados en esta categoría es necesario compilar el código para la ejecución de las pruebas.
  5. Violaciones.
    • “Issues”. Número de violaciones o malas prácticas en el código
    • Cumplimiento de reglas (%): Se calcula con la siguiente fórmula:

100 -((Violaciones ponderadas / Líneas de código) * 100)

Las violaciones ponderadas son la suma de todas las violaciones multiplicadas por su severidad (10 para las violaciones bloqueantes, 5 para las críticas, 3 para las mayores y 1 para las menores). Estos valores pueden ser modificados cuando accedemos como administradores.

 Deuda Técnica

Una de las medidas que no podemos obviar de Sonarqube es la deuda técnica. Es un valor en días que vendría a ser el tiempo aproximado que nos llevaría subsanar todos los problemas encontrados en nuestro software. Según la entrada de wikipedia, es un eufemismo tecnológico que hace referencia a las consecuencias de un desarrollo apresurado de software o un despliegue descuidado de hardware.

sonar2

El origen del término fue propuesto por Ward Cunningham en 1992. En el siguiente vídeo habla sobre este término.

En definitiva, Sonarqube nos va a ayudar a mantener una buena calidad del software construido, comparando las diferentes versiones y almacenando un histórico de las métricas informadas. Hoy en día es una herramienta clave, de uso casi obligado para evaluar el código entregado y liberado a nuestros clientes.

MongoDB para Principiantes

Este post pretende ser una introducción a MongoDB (MongoDB para principiantes), su modelo de datos, sus comandos de shell y sus consultas.

Últimamente he venido interesándome por el mundo de las bases de datos noSQL y más concretamente sobre MongoDB, que es una de las más utilizadas en entornos de producción, y en empresas como Foursquare y Codecademy. Este post pretende ser una introducción a MongoDB (MongoDB para principiantes), su modelo de datos, sus comandos de shell y sus consultas.

MongoDB (del inglés “humongous”, enorme) es una base de datos NoSQL, que en vez de guardar los datos en tablas, como en las bases de datos relacionales, se almacenan en estructuras de datos JSON.

Comenzó a desarrollarse en octubre de 2007 por la compañía 10gen. En 2009 se lanzó como producto independiente publicado con licencia de código abierto. Actualmente hay versiones para Windows, Linux, OSX y Solaris.

DataModel

Una instalación de MongoDB alberga una o varias bases de datos,y cada una de ellas un conjunto de coleccciones. A su vez cada colección alberga uno o varios (pudiendo ser un número enorme de ellos) documentos. Un documento es cada registro existente en una colección y la unidad básica de datos en MongoDB. Son análogos a objetos JSON pero en base de datos se almacenan en un formato más rico conocido como BSON (Binary JSON). La estructura de un documento se compone de pares “clave-valor“, separadas por “:”:

{
   field1: value1,
   field2: value2,
   field3: value3,
   ...
   fieldN: valueN
}

Cada valor, a su vez, puede ser otro documento. A continuación se muestra un ejemplo:

{
    "_id": ObjectId("4efa8d2b7d284dad101e4bc7"),
    "Last Name": "Johnson",
    "First Name": "Michael",
    "Age": 29,
    "Address": {
        "Street": "1 chemin des Loges",
        "City": "VERSAILLES"
    }
}

El campo “_id” es único en la colección. Si no lo incluimos en el documento a la hora de insertarlo en la colección, MongoDB asignará uno por defecto.

Los documentos utilizan un esquema dinámico. Esto quiere decir que los documentos dentro de una misma colección no necesitan tener los mismos campos ni estructura, y los campos comunes pueden tener distintos tipos de datos. Esta flexibilidad permite elegir el modelado de datos que más se adapte a la aplicación y a sus requisitos de rendimiento. El siguiente documento podría almacenarse junto al anterior ejemplo en la misma colección:

{
    "_id": ObjectId("d2b7d24efa884de4bc7ad101"),
    "Last Name": "Allison",
    "First Name": "Robert",
    "Hobbies": ["music", "sports"]
}

Instalación

Lo primero es descargar el software desde la página correspondiente. Existen versiones para los sistemas operativos más utilizados (Windows, Linux, OSX y Solaris) en versiones de 32 y 64 bits. La versión de 32 bits tiene el problema de estar limitada a 2Gb de datos entre todas las colecciones que almacene. Tras descargarnos el fichero zip o tgz, lo descomprimimos en el sistema de ficheros. En la carpeta principal de la instalación existirá una carpeta bin con las utilidades de la base de datos.

Para ejecutar MongoDB es necesario que exista en el directorio raíz (C:\ en Windows) la siguiente ruta C:\data\db como destino de los datos. En el momento de lanzar la ejecución de MongoDB podemos modificar la ubicación de esta ruta. A continuación ejecutamos desde línea de comandos

C:\mongodb\bin\mongod.exe

Este comando lanzará el proceso de MongoDB y si todo va bien aparecerá el mensaje “waiting for connections”. Para especificar otra ruta para los datos lo haremos indicando el directorio de datos tras el parámetro –dbpath:

C:\mongodb\bin\mongod.exe --dbpath d:\test\mongodb\data

También es posible ejecutar MongoDB como un servicio de Windows. Para instalarlo como servicio

Mongo Shell

Desde otra consola de comandos ejecutamos el siguiente comando:

C:\mongodb\bin\mongo.exe

Mongo shell (mongo.exe) conectará con el proceso mongod.exe que está ejecutando en la máquina local en el puerto 27017 por defecto. Para comprobar que está todo correcto ejecutamos los siguientes comandos:

db.test.save( { a: 1 } )
db.test.find()

El comando save ejecutado sobre la colección test, guarda el documento JSON pasado como parámetro a la función. Después de ejecutar el comando find(), obtenemos el único documento de la colección. A ese documento, como ya habíamos apuntado anteriormente MongoDB le añade un id único:

{"_id" : ObjectId("52fa4fe0d5ac743a52aa98e1"), "a" : 1 }

Por defecto usamos la base de datos test. Para ver las bases de datos utilizamos los siguientes comandos:

> show dbs
curso 0.203125GB
enron 1.953125GB
local 0.078125GB
test 0.203125GB
> use enron
switched to db enron

Junto al nombre de la base de datos, aparece el tamaño que ocupa en el sistema de ficheros. El comando use enron, cambia la base de datos de trabajo y sobre la que se ejecutan las operaciones de la shell. Para visualizar las colecciones de una base de datos ejecutamos el comando:

> show collections
messages
system.indexes

Hay que señalar que no existe ningún comando para crear una base de datos, pero podemos hacerlo con el comando use nombrenuevadb, e insertar un documento en una colección con save. MongoDB creará tanto la base de datos como la colección:

> use customers
switched to db customers
> db.clientes.save({"nombre":"juan"})
> show dbs
curso 0.203125GB
customers 0.203125GB
enron 1.953125GB
local 0.078125GB
test 0.203125GB
> db.clientes.find()
{ "_id" : ObjectId("531995937efc2c88b31af841"), "nombre" : "juan" }

Operaciones CRUD

Definimos operaciones CRUD como las operaciones para crear, leer, actualizar y borrar (Create, Read, Update and Delete) .

Consultas

Para realizar queries, MongoDB provee el método db.collection.find(), siendo collection el nombre de la colección a consultar:

Obtener todos los documentos de una colección

db.inventory.find()

Obtener todos los documentos de una colección que cumplen el valor para el tipo especificado {<field>:<value>}. Se puede indicar más de un valor para el campo con $in

db.inventory.find({tipo:"juguetes"})
db.inventory.find({tipo: { $in: ['comida', 'juguetes'] }})

Obtener todos los documentos de una colección que cumplen más de un valor (AND) para los tipos especificados {<field>:<value>}. Se pueden comparar valores con $lt (menor que) y $gt (mayor que).

db.inventory.find({tipo:"juguetes", precio: { $lt: 9.95 }})

Se pueden configurar queries con operadores OR.

db.inventory.find(
                   { $or: [
                            { qty: { $gt: 100 } },
                            { price: { $lt: 9.95 } }
                          ]
                   }
                 )

Y combinaciones de AND y OR.

db.inventory.find( { type: 'food', $or: [ { qty: { $gt: 100 } },
                                            { price: { $lt: 9.95 } 
                                          } ]
                   } )

Para retornar unos campos específicos en la consulta, los indicamos como segundo parámetro del método find. En el ejemplo sólo retorna los campos item y qty:

db.inventory.find( { type: 'food' }, { item: 1, qty: 1 } )

Para indicar que un campo no queremos que se retorne en la consulta en vez de un 1 asignamos un 0.

db.inventory.find( { type: 'food' }, { item: 1, qty: 1, _id:0 } )

Si queremos que devuelva todos los campos excepto los excluidos, únicamente indicamos éstos.

db.inventory.find( { type: 'food' }, { qty: 0 } )

Inserciones

Se pueden insertar documentos a través de varios métodos. El primero con la llamada al método insert() con el documento a insertar

db.inventory.insert( { _id: 10, type: "misc", item: "card", qty: 15 
} )

El segundo método es a través de la llamada al método update() con el flag upsert:true

db.inventory.update(
                     { type: "book", item : "journal" },
                     { $set : { qty: 10 } },
                     { upsert : true }
                   )

Intenta actualizar el registro Si no especificamos la clave _id, Mongo nos creará una por defecto que además es única

El tercer método es invocando al método save() con el documento a insertar. Si el documento pasado no contiene _id, mongo creará igualmente una clave única.

db.inventory.save( { type: "book", item: "notebook", qty: 40 } )

Actualizaciones

El método update() actualiza un único documento que coincide con el criterio de búsqueda pasado como primer parámetro, con los datos pasados en el documento del segundo parámetro. Podemos pasar la opción multi : true para indicar que se guarden varios.

db.inventory.update( { type : "book" }, { $inc : { qty : -1 } },
   { multi: true }
)

También se puede actualizar un documento por su clave “_id” mediante el método save()

db.inventory.save( { _id: 10, type: "misc", item: "placard"  })

Borrados

El borrado de todos los documentos se hace con remove() o drop()

db.inventory.remove()
db.inventory.drop()

Para el borrado de documentos que coinciden con un criterio de búsqueda

db.inventory.remove( { tipo: "comida" } )

Para profundizar en éste y otros temas podemos acudir al manual en línea de MongoDB o apuntarse a alguno de sus cursos gratuitos.