Al desarrollar una aplicación crítica, es importante prepararse para imprevistos que puedan ocurrir en producción. Esto incluye consultas lentas inesperadas, índices faltantes o un aumento brusco del volumen de trabajo.
MongoDB Atlas te ayuda a desarrollar una aplicación resistente al proporcionarte funcionalidades listas para usar que te permiten prepararte proactivamente y responder de forma reactiva a diversas situaciones. Para construir una aplicación resiliente, se recomienda configurar la implementación de MongoDB con los siguientes resiliencia de clúster y las mejores prácticas de aplicaciones y lado del cliente.
Resiliencia de clústeres
Para mejorar la resiliencia de tu clúster, actualiza tu clúster a MongoDB 8.0. MongoDB 8.0 introduce las siguientes mejoras de rendimiento y nuevas funcionalidades relacionadas con la resiliencia:
Filtros de rechazo de operación para mitigar reactivamente las costosas query
Tiempos de espera a nivel de clúster para protección proactiva contra operaciones de lectura costosas
Mejor aislamiento de carga de trabajo con el comando moveCollection
Gestión de memoria mejorada
Para ejecutar tu aplicación de forma segura en producción, es importante asegurarse de que la utilización de la memoria permita un margen de maniobra. Si un nodo se queda sin memoria disponible, puede volverse susceptible al Linux Out of Memory Killer que termina el mongod procesar.
MongoDB 8.0 utiliza un TCMalloc actualizado para todas las implementaciones de forma automática, lo que reduce el crecimiento promedio de la fragmentación de memoria con el tiempo. Esta menor fragmentación mejora la estabilidad operativa durante picos de carga y se traduce en una utilización de memoria mejorada en general.
Filtros de rechazo de operaciones
Una operación intensiva en recursos no intencionada puede causar problemas en la producción si no se gestiona rápidamente.
MongoDB 8.0 permite minimizar el impacto de estas operaciones mediante filtros de rechazo de operaciones. Estos filtros permiten configurar MongoDB para que rechace la ejecución de consultas hasta que se vuelvan a habilitar las consultas con esa forma de consulta.
En otras palabras, una vez que se identifica una consulta lenta, no es necesario esperar a que los equipos de la aplicación corrijan sus consultas para contener su impacto. En cambio, si se detecta una consulta con bajo rendimiento en el Analizador de Consultas, el Panel de Rendimiento en Tiempo Real o los registros de consultas, se puede establecer un filtro de rechazo para esa forma de consulta. MongoDB impide entonces que se ejecuten nuevas instancias de esa forma de consulta entrante. Una vez corregida la consulta, se puede volver a habilitar.
Debes utilizar un filtro de rechazo de operaciones si deseas:
Contenga el impacto de las consultas lentas rápidamente mientras se está trabajando en la solución.
Prioriza cargas de trabajo más importantes durante tiempos de sobrecarga rechazando queries menos importantes.
Dale tiempo al clúster para recuperarse si está cerca del máximo uso de recursos.
Identifique y rechace consultas lentas en la interfaz de usuario de Atlas
Para utilizar un filtro de rechazo de operaciones en la interfaz de usuario de Atlas:
En Atlas, ve a Clusters página para tu proyecto.
Si aún no se muestra, seleccione la organización que contiene su proyecto deseado en el menú Organizations de la barra de navegación.
Si aún no aparece, selecciona el proyecto deseado en el menú Projects de la barra de navegación.
En la barra lateral, haz clic en Clusters en la sección Database.
La página de clústeres se muestra.
Vaya al Generador de perfiles de consultas para el clúster especificado dentro del proyecto actual.
Haz clic en el nombre del clúster para abrir la barra lateral Cluster.
Haz clic en Query Insights en la barra lateral Cluster.
Haz clic en la pestaña Query Profiler.
Rechaza las operaciones de una forma del query específica.
Utilice setQuerySettings en su método db.adminCommand() para queryShapeHash pasar, que especifica la forma de consulta que desea rechazar.
Nota
Debe tener el rol atlasAdmin para setQuerySettings usar.
Para ver un ejemplo, consulte Bloquear queries lentas con filtros de rechazo de operaciones.
Supervisa tus consultas después de un rechazo o expiración
Posteriormente, puede supervisar el rendimiento de sus consultas en la sección Métricas de la barra lateral del clúster:
En Atlas, ve a la página Clusters de tu proyecto.
Si aún no se muestra, seleccione la organización que contiene su proyecto deseado en el menú Organizations de la barra de navegación.
Si aún no aparece, selecciona el proyecto deseado en el menú Projects de la barra de navegación.
En la barra lateral, haz clic en Clusters en la sección Database.
La página de clústeres se muestra.
Seleccione Operation Throttling.
En MongoDB Metrics, haz clic en Operation Throttling.
Con esta métrica, la gráfica de MongoDB muestra lo siguiente:
Killed, que muestra la cantidad de operaciones de lectura que MongoDB elimina con el tiempo debido a que exceden el tiempo de espera predeterminado del clúster.
Rejected-que muestra la cantidad de operaciones que MongoDB rechaza a lo largo del tiempo porque la query coincide con el filtro de rechazo definido por el usuario.
Tiempos de espera a nivel de clúster para operaciones de lectura
Es importante asegurarse de que su proceso de desarrollo considere cuidadosamente la eficiencia de las queries antes de que lleguen a producción. Las excepciones pueden ocurrir siempre, pero tener una mitigación proactiva contra queries ineficientes puede ayudar a evitar problemas de rendimiento del clúster.
Con MongoDB 8.0, puedes proteger tus consultas de operaciones no indexadas con el defaultMaxTimeMS del lado del servidor que ingresa al clúster. Si una operación excede este tiempo de espera, MongoDB cancela la operación para evitar que las consultas se ejecuten durante demasiado tiempo y consuman recursos. Esto te permite:
Traslada la responsabilidad de establecer límites de tiempo de los equipos de aplicaciones individuales a los equipos enfocados en bases de datos.
Minimiza el impacto de un escaneo de colección si a la query le falta un índice.
Disponer de una mitigación de última ronda contra operaciones costosas que llegan a producción.
Si tienes queries que requieren un tiempo de espera diferente, como las queries de análisis, puedes sobrescribirlas configurando el tiempo de espera a nivel de operación con el método maxTimeMS.
Establecer el tiempo de espera predeterminado para las operaciones de lectura en la API de administración de Atlas
Para establecer el parámetro defaultMaxTimeMS a través de la API de Administración de Atlas, consulta Actualizar opciones avanzadas de configuración para un clúster.
Establecer el tiempo de espera predeterminado para las operaciones de lectura en la interfaz de usuario de Atlas
Para configurar el parámetro en la interfaz de usuario de defaultMaxTimeMS Atlas:
En Atlas, ve a la página Clusters de tu proyecto.
Si aún no se muestra, seleccione la organización que contiene su proyecto deseado en el menú Organizations de la barra de navegación.
Si aún no aparece, selecciona el proyecto deseado en el menú Projects de la barra de navegación.
En la barra lateral, haz clic en Clusters en la sección Database.
La página de clústeres se muestra.
Navegue a sus opciones de configuración.
Si tienes un clúster existente, navega a la página Editar clúster.
Si está creando un nuevo clúster, en la lista desplegable Select a version, seleccione MongoDB 8.0.
Haga clic en Additional Settings.
Desplázate hacia abajo y haz clic en More Configuration Options.
Para ver el comportamiento de las operaciones finalizadas, consulta Supervisa tus queries después del rechazo o tiempo de espera. Para obtener más información, consulta defaultMaxTimeMS y Configura el tiempo de espera por defecto para operaciones de lectura.
Aísla el impacto de colecciones ocupadas no fragmentadas
Lafragmentación permite escalar el clúster horizontalmente. Con MongoDB, se pueden fragmentar algunas colecciones, mientras que otras del mismo clúster permanecen sin fragmentar. Al crear una base de datos, el fragmento del clúster con la menor cantidad de datos se selecciona como el fragmento principal de forma predeterminada. Todas las colecciones sin fragmentar de esa base de datos residen en ese fragmento principal de forma predeterminada. Esto puede provocar un aumento del tráfico al fragmento principal a medida que aumenta la carga de trabajo, especialmente si este se centra en las colecciones sin fragmentar del fragmento principal.
Para distribuir mejor esta carga de trabajo, MongoDB 8.0 permite mover una colección no particionada a otras particiones desde la partición primaria mediante el comando moveCollection. Esto permite ubicar colecciones activas y ocupadas en particiones con un menor uso esperado de recursos. Con esto, puedes:
Optimiza el rendimiento en cargas de trabajo más grandes y complejas.
Lograr una mejor utilización de los recursos.
Distribuye la fecha de manera más uniforme entre las particiones.
Recomendamos aislar tu colección en las siguientes circunstancias:
Si tu partición primaria experimenta una carga de trabajo significativa debido a la presencia de varias colecciones no particionadas de alto rendimiento.
Se anticipa que una colección sin particiones experimentará un crecimiento futuro, que podría convertirse en un cuello de botella para otras colecciones.
Está ejecutando un diseño de implementación de una colección por clúster y desea aislar a esos clientes en función de la prioridad o las cargas de trabajo.
Tus particiones tienen más datos de lo proporcional debido a la cantidad de colecciones no fragmentadas ubicadas en ellos.
Para aprender a mover una colección no particionada con mongosh, consulta Mover una colección.
Mejores prácticas para aplicaciones y clientes
Puedes configurar las funcionalidades de tus implementaciones de MongoDB y de las librerías del driver para crear una aplicación resistente que pueda soportar interrupciones del servicio de red y eventos de failover. Para escribir un código de aplicación que aproveche al máximo las capacidades siempre activas de MongoDB Atlas, debes realizar las siguientes tareas:
Utilice una
majoritypreocupación de escritura y una preocupación de lectura que tenga sentido para su aplicación.Gestionar errores en su aplicación.
Instale las Librerías de clientes más recientes
Instale las últimas Librerías de clientes para su lenguaje desde Librerías de clientes de MongoDB. Las librerías cliente conectan y transmiten consultas desde tu aplicación a tu base de datos. Utilizar las últimas Librerías de clientes permite acceder a las últimas funcionalidades de MongoDB.
Luego, en tu aplicación, importa la dependencia:
Si usas Maven, añade lo siguiente a tu lista de dependencias pom.xml:
<dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongodb-driver-sync</artifactId> <version>4.0.1</version> </dependency> </dependencies>
Si está utilizando Gradle, añada lo siguiente a su lista de dependencias build.gradle:
dependencies { compile 'org.mongodb:mongodb-driver-sync:4.0.1' }
// Latest 'mongodb' version installed with npm const MongoClient = require('mongodb').MongoClient;
# Install the latest 'pymongo' version with pip and # import MongoClient from the package to establish a connection. from pymongo import MongoClient
Cadenas de conexión
Nota
Atlas proporciona una cadena de conexión preconfigurada. Para conocer los pasos para copiar la cadena preconfigurada, consulte Cadenas de conexión proporcionadas por Atlas.
Utiliza una cadena de conexión que especifique todos los nodos en tu clúster de Atlas para conectar tu aplicación a tu base de datos. Si tu clúster realiza una elección de set de réplicas y se elige un nuevo primario, una cadena de conexión que especifica todos los nodos de su clúster detecta el nuevo primario sin lógica de la aplicación.
Puede especificar todos los nodos de su clúster utilizando:
el formato de cadena de conexión estándar, o
el Formato de Conexión DNS lista de nodos iniciales (recomendado con Atlas).
La cadena de conexión también puede especificar opciones, especialmente retryWrites y writeConcern.
Atlas puede generar un Cadena de conexiónSRV para clústeres fragmentados que utilizan los balanceadores de carga de su servicio de punto final privado. Al usar una cadena de conexión optimizada, Atlas limita el número de conexiones por mongos entre su aplicación y su clúster fragmentado. La limitación de conexiones por mongos mejora el rendimiento durante picos de conexión.
Para obtener más información sobre las cadenas de conexión optimizadas para clústeres fragmentados detrás de un nodo privado, consulta ¿Cómo puedo optimizar el rendimiento de la conexión para clústeres fragmentados con nodos privados?
Cadenas de conexión proporcionadas por Atlas
Si copias tu cadena de conexión desde la interfaz de tu clúster de Atlas, la cadena de conexión está preconfigurada para tu clúster, utiliza el formato de lista de semillas DNS y la inclusión de las opciones recomendadas de retryWrites y w (nivel de confirmación de escritura (write concern)) para obtener resiliencia.
Para copiar la URI de su cadena de conexión desde Atlas:
En Atlas, ve a la página Clusters de tu proyecto.
Si aún no se muestra, seleccione la organización que contiene su proyecto deseado en el menú Organizations de la barra de navegación.
Si aún no aparece, selecciona el proyecto deseado en el menú Projects de la barra de navegación.
En la barra lateral, haz clic en Clusters en la sección Database.
La página de clústeres se muestra.
Copiar la cadena de conexión URI.
Copia la cadena de conexión o el ejemplo completo del controlador en el código de tu aplicación. Debes proporcionar credenciales de usuario de base de datos.
Nota
Esta guía utiliza autenticación SCRAM a través de una cadena de conexión. Para aprender sobre el uso de los certificados X.509 para autenticarse, consulta X.509.
Utiliza tu cadena de conexión para crear un cliente de MongoDB en la aplicación:
// Copy the connection string provided by Atlas String uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI MongoClient client = MongoClients.create(uri);
// Copy the connection string provided by Atlas const uri = <your Atlas connection string>; // Instantiate the MongoDB client with the URI const client = new MongoClient(uri);
# Copy the connection string provided by Atlas uri = <your Atlas connection string> # Pass your connection string URI to the MongoClient constructor client = MongoClient(uri)
Escrituras y lecturas reintentables
Nota
MongoDB vuelve a intentar tanto los guardados como las lecturas una vez por defecto.
Escrituras reintentables
Utiliza escrituras reintentables para reintentar ciertas operaciones de escritura una sola vez si fallan. Si copiaste tu cadena de conexión desde Atlas, incluye "retryWrites=true". Si proporcionas tu propia cadena de conexión, incluye "retryWrites=true" como un parámetro de consulta.
Reintentar la escritura una sola vez es la mejor estrategia para gestionar errores de red transitorios y elecciones de conjuntos de réplicas en los que la aplicación no puede encontrar temporalmente un nodo principal en buen estado. Si el reintento tiene éxito, la operación en su conjunto se completa correctamente y no se devuelve ningún error. Si la operación falla, probablemente se deba a:
Un error de red persistente
Un comando no válido
Cuando una operación falla, su aplicación necesita gestionar el error ella misma.
Lecturas reintentables
Las operaciones de lectura se reintentan automáticamente una sola vez si fallan. No se requiere configuración adicional para reintentar las lecturas.
Guardar y nivel de consistencia de lectura
Puede ajustar la consistencia y la disponibilidad de su aplicación mediante preocupaciones de escritura y lectura. Unas preocupaciones más estrictas implican que las operaciones de la base de datos esperan garantías de consistencia de datos más sólidas, mientras que una mayor flexibilidad en los requisitos de consistencia proporciona una mayor disponibilidad.
Ejemplo
Si su aplicación gestiona saldos monetarios, la coherencia es sumamente importante. Puedes usar las preocupaciones de escritura y el nivel de consistencia de lectura de majority para asegurarte de nunca leer datos obsoletos o datos que puedan ser revertidos.
Alternativamente, si tu aplicación registra datos de temperatura de cientos de sensores cada segundo, es posible que no te preocupe si lees datos que no incluyen las lecturas más recientes. Puedes relajar los requisitos de coherencia y proporcionar acceso más rápido a esos datos.
Nivel de confirmación de escritura
Puede configurar el nivel de preocupación de escritura de su conjunto de réplicas de Atlas mediante el URI de la cadena de conexión. Use una majority preocupación de escritura para garantizar que sus datos se escriban correctamente en su base de datos y se conserven. Este es el valor predeterminado recomendado y suficiente para la mayoría de los casos de uso. Si copió su cadena de conexión de Atlas, esta "w=majority" incluye.
Cuando use un nivel de confirmación de escritura (write concern) que requiera confirmación, como majority, también puede especificar un límite máximo de tiempo para que las escrituras alcancen ese nivel de confirmación:
El parámetro de la cadena de conexión wtimeoutMS para todas las escrituras, o
La opción wtimeout para una única operación de guardar.
El uso o no de un límite de tiempo y el valor que utilice dependerán del contexto de su aplicación.
Importante
Si no especifica un límite de tiempo para las escrituras y el nivel de preocupación por la escritura es inalcanzable, la operación de escritura se bloqueará indefinidamente.
readConcern
Se puede configurar el nivel de consistencia de lectura del set de réplicas de Atlas a través de la URI de cadena de conexión. La nivel de consistencia de lectura ideal depende de los requisitos de tu aplicación, pero el valor por defecto es suficiente para la mayoría de los casos de uso. No se requiere ningún parámetro de cadena de conexión para usar los niveles de consistencia de lectura por defecto.
Especificar un nivel de consistencia de lectura puede mejorar las garantías en torno a los datos que su aplicación recibe de Atlas.
Nota
La combinación específica de problemas de escritura y lectura que utiliza su aplicación afecta las garantías de orden de operación. Esto se denomina consistencia causal. Para obtener más información sobre las garantías de consistencia causal, consulte Consistencia causal y Problemas de lectura y escritura.
Error Handling
Los comandos no válidos, las interrupciones del servicio y los errores de red que no son gestionados por escrituras reintentables devuelven errores. Consulte la documentación de la API de su controlador para conocer los detalles del error.
Por ejemplo, si una aplicación intenta insertar un documento que contiene un valor _id que ya se utiliza en la colección de la base de datos, tu driver devuelve un error que incluye:
Unable to insert due to an error: com.mongodb.MongoWriteException: E11000 duplicate key error collection: <db>.<collection> ...
{ "name": : "MongoError", "message": "E11000 duplicate key error collection on: <db>.<collection> ... ", ... }
pymongo.errors.DuplicateKeyError: E11000 duplicate key error collection: <db>.<collection> ...
Sin una gestión adecuada de errores, un error podría evitar que tu aplicación realice el procesamiento de solicitudes hasta que se reinicie.
Tu aplicación debe gestionar errores sin fallos ni efectos secundarios. En el ejemplo anterior de una aplicación que inserta un _id duplicado en una colección, esa aplicación podría gestionar los errores de la siguiente manera:
// Declare a logger instance from java.util.logging.Logger private static final Logger LOGGER = ... ... try { InsertOneResult result = collection.insertOne(new Document() .append("_id", 1) .append("body", "I'm a goofball trying to insert a duplicate _id")); // Everything is OK LOGGER.info("Inserted document id: " + result.getInsertedId()); // Refer to the API documentation for specific exceptions to catch } catch (MongoException me) { // Report the error LOGGER.severe("Failed due to an error: " + me); }
... collection.insertOne({ _id: 1, body: "I'm a goofball trying to insert a duplicate _id" }) .then(result => { response.sendStatus(200) // send "OK" message to the client }, err => { response.sendStatus(400); // send "Bad Request" message to the client });
... try: collection.insert_one({ "_id": 1, "body": "I'm a goofball trying to insert a duplicate _id" }) return {"message": "User successfully added!"} except pymongo.errors.DuplicateKeyError as e: print ("The insert operation failed:", e)
La operación de inserción en este ejemplo arroja un error de "clave duplicada" la segunda vez que se invoca porque el campo _id debe ser único. Se detecta el error, se notifica al cliente y la aplicación sigue funcionando. Sin embargo, la operación de inserción falla y depende de ti decidir si mostrar un mensaje al usuario, reintentar la operación o hacer otra cosa.
Siempre se deben registrar los errores. Las estrategias comunes para el procesamiento adicional de errores incluyen:
Devuelva el error al cliente con un mensaje de error. Esta es una buena estrategia cuando no puedes resolver el error y necesitas informar a un usuario de que no se puede completar una acción.
Escribe en una base de datos de copias de seguridad. Esta es una buena estrategia cuando no puedes resolver el error pero no quieres arriesgarte a perder los datos de la solicitud.
Reintente la operación más allá del único reintento predeterminado. Esta es una buena estrategia cuando puede resolver la causa de un error mediante programación y luego reintentarla.
Debe seleccionar las mejores estrategias para el contexto de su aplicación.
Ejemplo
En el ejemplo de un error de clave duplicada, debe registrar el error pero no volver a intentar la operación porque nunca tendrá éxito. En su lugar, puedes guardar en una base de datos alternativa y revisar el contenido de esa base de datos en un momento posterior para garantizar que no se pierda ninguna información. El usuario no necesita hacer nada más y los datos están registrados, por lo que puedes optar por no enviar un mensaje de error al cliente.
Planificación para errores de red
Devolver un error puede ser un comportamiento deseable cuando una operación pueda quedar colgada indefinidamente e impedir que tu aplicación ejecute nuevas operaciones. Puedes usar el método maxTimeMS para establecer un límite de tiempo en operaciones individuales, devolviendo un error para que tu aplicación lo gestione si se excede ese límite de tiempo.
El límite de tiempo que se establezca para cada operación depende del contexto de esa operación.
Ejemplo
Si tu aplicación lee y muestra información de producto sencilla desde una colección inventory, puedes tener la confianza razonable de que esas operaciones de lectura solo toman un momento. Una query que se ejecuta inusualmente durante mucho tiempo es un buen indicador de que hay un problema de red persistente. Configurar maxTimeMS en esa operación a 5000, o 5 segundos, significa que tu aplicación recibe retroalimentación tan pronto como estés seguro de que hay un problema de red.
Prueba de conmutación por error
En el espíritu de pruebas de caos, Atlas realizará elecciones de set de réplicas automáticamente para tareas de mantenimiento periódicas y ciertos cambios de configuración.
Para comprobar si tu aplicación es resiliente a las elecciones del set de réplicas, prueba el proceso de failover simulando un evento de failover.
Aplicación de ejemplo resiliente
La aplicación de ejemplo reúne las siguientes recomendaciones para garantizar la resiliencia frente a interrupciones del servicio de red y eventos de conmutación por error:
Utilice la cadena de conexión proporcionada por Atlas con escrituras reintentables, nivel de confirmación de escritura de mayoría y nivel de consistencia de lectura por defecto.
Especificar un límite de operation time con el método maxTimeMS. Para obtener instrucciones sobre cómo configurar
maxTimeMS, consulta tu documentación del driver.Gestione errores por claves duplicadas y "timeouts".
La aplicación es una API HTTP que permite a los clientes crear o listar registros de usuarios. Expone un punto final que acepta solicitudes GET y POST:http://localhost::3000
Método | Endpoint | Descripción |
|---|---|---|
|
| Obtiene una lista de nombres de usuario de una colección |
|
| Requiere un |
Nota
1 // File: App.java 2 3 import java.util.Map; 4 import java.util.logging.Logger; 5 6 import org.bson.Document; 7 import org.json.JSONArray; 8 9 import com.mongodb.MongoException; 10 import com.mongodb.client.MongoClient; 11 import com.mongodb.client.MongoClients; 12 import com.mongodb.client.MongoCollection; 13 import com.mongodb.client.MongoDatabase; 14 15 import fi.iki.elonen.NanoHTTPD; 16 17 public class App extends NanoHTTPD { 18 private static final Logger LOGGER = Logger.getLogger(App.class.getName()); 19 20 static int port = 3000; 21 static MongoClient client = null; 22 23 public App() throws Exception { 24 super(port); 25 26 // Replace the uri string with your MongoDB deployment's connection string 27 String uri = "<atlas-connection-string>"; 28 client = MongoClients.create(uri); 29 30 start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); 31 LOGGER.info("\nStarted the server: http://localhost:" + port + "/ \n"); 32 } 33 34 public static void main(String[] args) { 35 try { 36 new App(); 37 } catch (Exception e) { 38 LOGGER.severe("Couldn't start server:\n" + e); 39 } 40 } 41 42 43 public Response serve(IHTTPSession session) { 44 StringBuilder msg = new StringBuilder(); 45 Map<String, String> params = session.getParms(); 46 47 Method reqMethod = session.getMethod(); 48 String uri = session.getUri(); 49 50 if (Method.GET == reqMethod) { 51 if (uri.equals("/")) { 52 msg.append("Welcome to my API!"); 53 } else if (uri.equals("/users")) { 54 msg.append(listUsers(client)); 55 } else { 56 msg.append("Unrecognized URI: ").append(uri); 57 } 58 } else if (Method.POST == reqMethod) { 59 try { 60 String name = params.get("name"); 61 if (name == null) { 62 throw new Exception("Unable to process POST request: 'name' parameter required"); 63 } else { 64 insertUser(client, name); 65 msg.append("User successfully added!"); 66 } 67 } catch (Exception e) { 68 msg.append(e); 69 } 70 } 71 72 return newFixedLengthResponse(msg.toString()); 73 } 74 75 static String listUsers(MongoClient client) { 76 MongoDatabase database = client.getDatabase("test"); 77 MongoCollection<Document> collection = database.getCollection("users"); 78 79 final JSONArray jsonResults = new JSONArray(); 80 collection.find().forEach((result) -> jsonResults.put(result.toJson())); 81 82 return jsonResults.toString(); 83 } 84 85 static String insertUser(MongoClient client, String name) throws MongoException { 86 MongoDatabase database = client.getDatabase("test"); 87 MongoCollection<Document> collection = database.getCollection("users"); 88 89 collection.insertOne(new Document().append("name", name)); 90 return "Successfully inserted user: " + name; 91 } 92 }
Nota
La siguiente aplicación de servidor utiliza Express, que debe agregar a su proyecto como dependencia antes de poder ejecutarlo.
1 const express = require('express'); 2 const bodyParser = require('body-parser'); 3 4 // Use the latest client libraries by installing & importing them 5 const MongoClient = require('mongodb').MongoClient; 6 7 const app = express(); 8 app.use(bodyParser.json()); 9 app.use(bodyParser.urlencoded({ extended: true })); 10 11 const uri = "mongodb+srv://<db_username>:<db_password>@cluster0-111xx.mongodb.net/test?retryWrites=true&w=majority"; 12 13 const client = new MongoClient(uri); 14 15 // ----- API routes ----- // 16 app.get('/', (req, res) => res.send('Welcome to my API!')); 17 18 app.get('/users', (req, res) => { 19 const collection = client.db("test").collection("users"); 20 21 collection 22 .find({}) 23 .maxTimeMS(5000) 24 .toArray((err, data) => { 25 if (err) { 26 res.send("The request has timed out. Please check your connection and try again."); 27 } 28 return res.json(data); 29 }); 30 }); 31 32 app.post('/users', (req, res) => { 33 const collection = client.db("test").collection("users"); 34 collection.insertOne({ name: req.body.name }) 35 .then(result => { 36 res.send("User successfully added!"); 37 }, err => { 38 res.send("An application error has occurred. Please try again."); 39 }) 40 }); 41 // ----- End of API routes ----- // 42 43 app.listen(3000, () => { 44 console.log(`Listening on port 3000.`); 45 client.connect(err => { 46 if (err) { 47 console.log("Not connected: ", err); 48 process.exit(0); 49 } 50 console.log('Connected.'); 51 }); 52 });
Nota
La siguiente aplicación web utiliza FastAPI. Para crear una nueva aplicación, se debe usar la estructura del archivo de muestra de FastAPI.
1 # File: main.py 2 3 from fastapi import FastAPI, Body, Request, Response, HTTPException, status 4 from fastapi.encoders import jsonable_encoder 5 6 from typing import List 7 from models import User 8 9 import pymongo 10 from pymongo import MongoClient 11 from pymongo import errors 12 13 # Replace the uri string with your |service| connection string 14 uri = "<atlas-connection-string>" 15 db = "test" 16 17 app = FastAPI() 18 19 20 def startup_db_client(): 21 app.mongodb_client = MongoClient(uri) 22 app.database = app.mongodb_client[db] 23 24 25 def shutdown_db_client(): 26 app.mongodb_client.close() 27 28 ##### API ROUTES ##### 29 30 def list_users(request: Request): 31 try: 32 users = list(request.app.database["users"].find().max_time_ms(5000)) 33 return users 34 except pymongo.errors.ExecutionTimeout: 35 raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="The request has timed out. Please check your connection and try again.") 36 37 38 def new_user(request: Request, user: User = Body(...)): 39 user = jsonable_encoder(user) 40 try: 41 new_user = request.app.database["users"].insert_one(user) 42 return {"message":"User successfully added!"} 43 except pymongo.errors.DuplicateKeyError: 44 raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Could not create user due to existing '_id' value in the collection. Try again with a different '_id' value.")