es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

La Mejor Manera de Construir una Colección en el Controlador Node Mongo desde un Directorio

Hice una pregunta similar ayer a esta enlace, pero la solución fue muy fácil y no abordó realmente mi problema fundamental de no entender el control de flujo en JavaScript asíncrono. La versión resumida de lo que estoy intentando hacer es construir una colección de MongoDB a partir de un directorio de archivos JSON. Lo tenía funcionando, pero modifiqué algo y ahora el flujo es tal que el programa se ejecuta por completo y, por lo tanto, cierra la conexión antes de que se ejecuten las llamadas asincrónicas insertOne(). Cuando las llamadas insertOne() finalmente se ejecutan, los datos no se ingresan y recibo advertencias sobre una excepción no controlada al usar una conexión cerrada.

Soy nuevo en esto, así que si lo que estoy haciendo no es una buena práctica (no lo es), por favor avísenme y estaré encantado de cambiar las cosas para que sean confiables. El código relevante se ve básicamente así:

fs.readDirSync(dataDir).forEach(async function(file){

//lógica para construir el objeto de datos desde el archivo JSON

console.log('Insertando objeto ' + obj['ID']);
let result = await connection.insertOne(obj);
console.log('Objeto ' + result.insertedId + ' insertado.');
})

Esto está envuelto en una función async que espero. Al colocar un mensaje console.log() al final del flujo del programa, seguido de un while(true);, he verificado que se imprimen todos los mensajes “Insertando objeto + obj[ID]”, pero no los siguientes mensajes “Objeto + result.insertedId + insertado” cuando el flujo llega al final del programa. Si quito el while(true); obtengo todos los mensajes de error, porque ya no estoy bloqueando y obviamente en ese punto el cliente está cerrado. En ningún caso se construye realmente la base de datos.

Entiendo que siempre hay curvas de aprendizaje, pero es realmente frustrante no poder hacer algo tan simple como el control de flujo. Solo estoy tratando de hacer algo tan simple como “recorrer cada archivo, realizar una función en cada archivo, cerrar y salir”, que es una programación básica. Entonces, ¿cuál es la mejor manera de marcar un punto en el que el control de flujo no pasará hasta que se completen todos los intentos de inserción de datos en la colección (ya sea exitosamente o no, porque idealmente puedo usar una bandera para marcar si hubo errores)?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El problema con el código actual es que no espera a que se completen todas las llamadas asincrónicas insertOne() antes de cerrar la conexión a la base de datos MongoDB. Una forma de asegurarse de que todas las inserciones se completen antes de cerrar la conexión es usar Promise.all() para esperar a que se resuelvan todas las promesas.

    Aquí hay una versión actualizada del código que utiliza Promise.all():

    async function buildCollection() {
      const files = fs.readdirSync(dataDir);
      const insertPromises = [];
    
      files.forEach(function (file) {
        // lógica para construir un objeto de datos a partir de un archivo JSON
        const obj = JSON.parse(fs.readFileSync(path.join(dataDir, file)));
    
        console.log('Insertando objeto ' + obj['ID']);
    
        insertPromises.push(connection.insertOne(obj).then(function (result) {
          console.log('Objeto ' + result.insertedId + ' insertado.');
        }));
      });
    
      try {
        await Promise.all(insertPromises);
        console.log('¡Todas las inserciones completadas!');
      } catch (error) {
        console.error('Error al insertar los datos:', error);
      } finally {
        connection.close();
        console.log('Conexión cerrada.');
      }
    }
    
    buildCollection();
    

    En este código actualizado, creamos un arreglo de promesas (insertPromises) para cada llamada a insertOne(), y luego usamos Promise.all() para esperar a que se resuelvan todas las promesas. La llamada a Promise.all() devuelve una nueva promesa que se resuelve con un arreglo de resultados cuando todas las promesas de entrada se han resuelto. Usamos await para esperar a que esta promesa se resuelva, y luego mostramos un mensaje que indica que todas las inserciones se han completado (o un mensaje de error si ocurrió un error). Finalmente, cerramos la conexión a la base de datos.

Comments are closed.