Cuando trabajamos con sensores que envían datos constantemente a una base de datos, surge un problema muy común: ¿cómo saber si debemos crear un nuevo documento o actualizar uno existente? MongoDB ofrece una solución elegante llamada upsert que combina ambas operaciones en una sola instrucción, eliminando la necesidad de consultas previas para tomar esa decisión.
¿Cómo se estructura la información de sensores IoT en MongoDB?
El caso presentado utiliza una colección llamada IoT dentro de una base de datos, donde cada documento representa las lecturas de un sensor específico para un día determinado [0:30]. La estructura incluye:
- Un identificador del sensor, por ejemplo
A001.
- Una fecha que indica el día de las lecturas.
- Un array de lecturas (readings) que acumula los valores registrados durante ese día.
La regla fundamental es que para un mismo sensor y un mismo día solo debe existir un documento. Si el sensor envía su primera lectura del día, se crea un documento nuevo. Si envía lecturas posteriores ese mismo día, simplemente se agregan al array de lecturas del documento ya existente [1:18].
¿Qué sucede al insertar la primera lectura del día?
Cuando llega la primera lectura de un sensor para una fecha nueva, se ejecuta un insertOne que crea el documento completo con el identificador del sensor, la fecha y la primera lectura dentro del array [2:35]. MongoDB genera automáticamente el ObjectId para ese documento.
¿Cómo se agrega una segunda lectura sin duplicar documentos?
Para la segunda lectura del mismo día, se utiliza updateOne con el operador $push, que permite agregar un nuevo elemento al array de lecturas [3:12]. Un detalle importante es que al usar $push, el valor debe enviarse directamente como un número y no como un sub-array, ya que de lo contrario se insertaría un array anidado dentro del array de lecturas.
¿Qué es el operador pop y cuándo usarlo?
El operador $pop permite eliminar el primer o el último elemento de un array [4:15]. Se utiliza pasándole el valor 1 para eliminar el último elemento, o -1 para eliminar el primero. En el caso práctico, se usó para corregir una lectura mal insertada que había quedado como un sub-array en lugar de un valor numérico directo.
Esta corrección ilustra un flujo habitual al trabajar con arrays en MongoDB: si algo se inserta incorrectamente, puedes removerlo con $pop y luego volver a insertarlo correctamente con $push.
¿Cómo funciona upsert para automatizar la decisión entre insert y update?
Sin upsert, la solución requeriría ejecutar primero un find con un count para verificar si ya existe un documento para ese sensor y esa fecha [5:30]. Si el resultado es cero, se ejecutaría un insertOne; si no, un updateOne. Funciona, pero agrega complejidad innecesaria.
Con upsert, simplemente se agrega el parámetro upsert: true dentro del método updateOne [6:20]. MongoDB se encarga automáticamente de:
- Crear el documento si no existe ninguno que cumpla con el filtro de sensor y fecha.
- Actualizar el documento existente si ya hay uno que coincida con la consulta.
El filtro del updateOne busca por sensor y fecha, y la operación usa $push para agregar la lectura. Con upsert activado, no importa si es la primera o la décima lectura del día: el mismo código maneja ambos escenarios [7:05].
¿Qué consideraciones tener al usar el Playground de MongoDB?
Al trabajar con el Playground de VS Code, es importante asegurarse de que el cursor esté posicionado al final del archivo antes de ejecutar [8:25]. Si el cursor queda sobre un bloque específico, el Playground solo ejecutará ese fragmento seleccionado, lo que puede dar resultados inesperados o la impresión de que una operación no se realizó.
El upsert es una herramienta poderosa para cualquier escenario donde los datos llegan de forma continua y necesitas garantizar que no se dupliquen documentos. Combinado con operadores como $push y $pop, tienes control total sobre cómo se gestionan los arrays dentro de tus documentos. Si has trabajado con sensores o datos en tiempo real, comparte tu experiencia y cómo resolviste casos similares.