MongoDB Academy · Lección

Operadores de elementos y comprobaciones de tipos

Consultará la existencia o el tipo de un campo mediante $exists y $type para gestionar datos opcionales o de tipos mixtos.

Lección 3 de 413 pasos

Operadores de elementos y comprobaciones de tipos es una lección gratuita de MongoDB Academy en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de MongoDB Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de MongoDB Academy incluye 4 lecciones en total.

Campos opcionales en esquemas flexibles

La flexibilidad del esquema de MongoDB significa que algunos documentos de una colección pueden tener campos que otros no tienen. Un documento de usuario podría tener un campo opcional phoneNumber: algunos usuarios lo proporcionaron y otros no. En SQL, manejaría esta situación con un valor NULL en cada fila. En MongoDB, el campo simplemente no existe en algunos documentos.

Esta diferencia tiene importantes consecuencias para las consultas. Los operadores de elementos de MongoDB, principalmente $exists y $type, le permiten consultar según la presencia o el tipo de un campo, en lugar de hacerlo según su valor.

$exists: comprobar la presencia de un campo

$exists: true coincide con los documentos que tienen el campo especificado, independientemente de su valor, incluso si el valor es null. $exists: false coincide con los documentos en los que el campo está completamente ausente.

Esta distinción es sutil, pero importante: un documento con { phone: null } sí coincide con { phone: { $exists: true } } porque el campo existe; simplemente tiene el valor null. Solo un documento que no tenga ningún campo phone coincide con { phone: { $exists: false } }.

// Find users who have provided a phone number (field exists)
db.users.find({ phone: { $exists: true } });

// Find users who never provided a phone number (field absent)
db.users.find({ phone: { $exists: false } });

// Key distinction:
// { phone: null }    => $exists: true (field exists, value is null)
// { name: 'Alice' }  => $exists: false (no phone field at all)

// Combined: field exists AND is not null
db.users.find({ phone: { $exists: true, $ne: null } });

Consultas de null frente a campos ausentes

El filtro de igualdad de MongoDB con null tiene un comportamiento doble que suele sorprender a los principiantes: { phone: null } coincide tanto con los documentos en los que phone es explícitamente null como con los documentos en los que phone no existe. Esto se debe a que MongoDB considera implícitamente null un campo ausente en las comparaciones de igualdad.

Si desea distinguir entre «el campo es null» y «el campo está ausente», combine $exists con $eq: null. En la mayoría de los casos prácticos, ambas situaciones significan «no se proporcionó un número de teléfono», por lo que puede tratarlas de la misma manera.

// Matches BOTH null and missing field:
db.users.find({ phone: null });
// Returns: { name: 'Alice', phone: null }
//      AND: { name: 'Bob' }  (no phone field)

// Only where field is explicitly null:
db.users.find({ phone: { $eq: null, $exists: true } });
// Returns: { name: 'Alice', phone: null }
// NOT: { name: 'Bob' } (missing field)

// Only where field is missing:
db.users.find({ phone: { $exists: false } });

$type: consultar por tipo BSON

MongoDB utiliza un esquema flexible, lo que significa que un campo como price podría ser un Number en la mayoría de los documentos, pero haberse almacenado accidentalmente como un String en algunos registros antiguos. El operador $type le permite filtrar documentos según el tipo BSON del valor de un campo.

Puede especificar los tipos por nombre (por ejemplo, 'string', 'int', 'date') o mediante el número de tipo BSON (por ejemplo, 2 para String y 16 para Int32). Usar nombres de tipos es más legible y la opción recomendada.

// Find documents where price is a string (data quality issue)
db.products.find({ price: { $type: 'string' } });
// These need to be fixed - price should be a number

// Find documents where price is a number (any numeric type)
db.products.find({ price: { $type: ['double', 'int', 'long', 'decimal'] } });
// $type accepts an array - matches any of the listed types

// Check for boolean
db.settings.find({ enabled: { $type: 'bool' } });

Nombres de tipos BSON comunes

Los nombres de tipos BSON más utilizados en las consultas con $type son:

  • 'double' — número de coma flotante de 64 bits (tipo numérico predeterminado de JS)
  • 'string' — cadena UTF-8
  • 'object' — documento incrustado (subobjeto)
  • 'array' — arreglo
  • 'binData' — datos binarios
  • 'objectId' — ObjectId
  • 'bool' — booleano
  • 'date' — fecha
  • 'null' — valor null
  • 'int' — entero de 32 bits
  • 'long' — entero de 64 bits
  • 'decimal' — Decimal128
// Real-world use: find documents where tags is an array
db.products.find({ tags: { $type: 'array' } });

// Find docs where createdAt is a date (not a string)
db.events.find({ createdAt: { $type: 'date' } });

// Audit: find any document where _id is not an ObjectId
db.users.find({ _id: { $not: { $type: 'objectId' } } });
// These might be docs with custom string _ids

El alias «number»

Un atajo útil es el alias de tipo 'number', que coincide con cualquier tipo numérico BSON: double, int, long y decimal. Equivale a escribir un arreglo con los cuatro nombres de tipos numéricos, pero resulta mucho más limpio.

Use 'number' cuando quiera encontrar todos los documentos en los que un campo sea cualquier tipo de número, independientemente de su precisión específica. Esto resulta especialmente útil en comprobaciones de calidad de datos en las que desea identificar campos que deberían ser numéricos, pero que se almacenaron accidentalmente como cadenas.

// 'number' alias matches double, int, long, decimal
db.products.find({ price: { $type: 'number' } });
// Same as: { price: { $type: ['double', 'int', 'long', 'decimal'] } }

// Data quality check: find price fields that are strings
// These should be numbers:
db.products.find({ price: { $type: 'string' } });

// Fix those docs:
db.products.find({ price: { $type: 'string' } }).forEach(doc => {
  db.products.updateOne(
    { _id: doc._id },
    { $set: { price: parseFloat(doc.price) } }
  );
});

Usar $exists en migraciones de esquemas

Las migraciones de esquemas en MongoDB suelen implicar agregar nuevos campos obligatorios a documentos existentes. $exists le ayuda a encontrar los documentos que aún deben actualizarse o que ya se migraron.

Un flujo de migración típico consiste primero en usar { newField: { $exists: false } } para encontrar todos los documentos antiguos y, después, agregar el nuevo campo con un valor predeterminado. Compruebe el progreso contando cuántos documentos todavía tienen $exists: false. Este enfoque de migración gradual funciona sin tiempo de inactividad, ya que el esquema flexible de MongoDB permite que las estructuras antiguas y nuevas de los documentos coexistan temporalmente.

// Migration: add 'timezone' field with default value to legacy users
async function migrateTimezone() {
  const batchSize = 1000;
  let processed = 0;

  while (true) {
    const result = await db.collection('users').updateMany(
      { timezone: { $exists: false } },  // Legacy docs without field
      { $set: { timezone: 'UTC' } },     // Add default
      { limit: batchSize }               // Process in batches
    );
    processed += result.modifiedCount;
    if (result.modifiedCount === 0) break;
  }
  console.log('Migrated:', processed);
}

Combinar $exists y $type

Puede combinar $exists y $type en una sola consulta para encontrar documentos en los que un campo exista Y tenga un tipo específico. Esto resulta útil en auditorías de calidad de datos en las que desea identificar los documentos cuyo campo tiene un tipo incorrecto, en lugar de los documentos en los que el campo simplemente está ausente.

Por ejemplo, en una colección donde age debería ser un número, podría querer contar por separado: (1) los documentos a los que les falta por completo el campo age, (2) los documentos en los que age es una cadena (un error de entrada de datos) y (3) los documentos en los que age es un número válido.

// Audit 'age' field data quality
const total = await db.collection('users').countDocuments({});

const missingAge = await db.collection('users')
  .countDocuments({ age: { $exists: false } });

const ageIsString = await db.collection('users')
  .countDocuments({ age: { $type: 'string' } });

const ageIsNumber = await db.collection('users')
  .countDocuments({ age: { $type: 'number' } });

console.log(`Total: ${total}, Missing: ${missingAge}, String: ${ageIsString}, Number: ${ageIsNumber}`);

$expr: comparaciones entre campos

El operador $expr le permite usar expresiones de agregación dentro de un filtro find() normal. Esto permite realizar comparaciones entre campos, algo que no es posible con los operadores de consulta estándar.

Por ejemplo, para «encontrar pedidos en los que el descuento sea superior al 50 % del precio original» es necesario comparar discount con una fracción calculada de originalPrice, dos campos del mismo documento. $expr permite expresar estas relaciones mediante operadores de expresión como $gt, $multiply y $divide.

// Find products where salePrice < originalPrice * 0.7 (>30% off)
db.products.find({
  $expr: {
    $lt: [
      '$salePrice',
      { $multiply: ['$originalPrice', 0.7] }
    ]
  }
});

// Find orders where quantity ordered > quantity in stock
db.orders.find({
  $expr: { $gt: ['$quantityOrdered', '$quantityInStock'] }
});

Indexación para consultas con $exists

Las consultas que usan $exists tienen un soporte de índices limitado. Un índice sobre un campo no ayuda con { field: { $exists: false } }: si el campo está ausente, no aparece en el índice, por lo que MongoDB debe examinar todos los documentos. Sin embargo, { field: { $exists: true } } puede usar un índice disperso: un índice disperso solo almacena entradas para los documentos que tienen el campo indexado, lo que permite buscar rápidamente los documentos existentes.

Use db.collection.createIndex({ field: 1 }, { sparse: true }) para crear un índice disperso cuando consulte con frecuencia documentos que tienen un campo opcional.

// Sparse index: only indexes docs where 'proSubscriptionId' exists
db.users.createIndex(
  { proSubscriptionId: 1 },
  { sparse: true }
);

// This query now uses the sparse index efficiently:
db.users.find({ proSubscriptionId: { $exists: true } });
// Only pro subscribers are in the index

// Regular (non-sparse) index would include null entries for all users
// Sparse index is smaller and faster for optional-field queries

Flujo de trabajo para auditar la calidad de los datos

Un flujo de trabajo práctico para auditar la calidad de los datos mediante y consiste en identificar primero todos los patrones de campos distintos de la colección para detectar incoherencias, categorizar después los documentos según sus tipos de campo y, por último, escribir llamadas específicas a updateMany para normalizar los datos.

El pipeline de agregación de MongoDB facilita la auditoría: mediante de un campo para contar cuántos documentos tienen cada tipo. Esto le ofrece una visión clara de los problemas de calidad de los datos antes de empezar a corregirlos.

// Audit: how many docs have price as each type?
db.products.aggregate([
  {
    : {
      _id: { : '' },  // Group by BSON type of price
      count: { : 1 }
    }
  }
]);
// Results like:
// [{ _id: 'double', count: 4820 },
//  { _id: 'string', count: 3 },
//  { _id: 'missing', count: 12 }]
// Now you know exactly what to fix!

Comprobación rápida

Compruebe su comprensión de los conceptos de MongoDB y las bases de datos NoSQL de esta lección.

Resumen de la lección

En esta lección ha aprendido: las consultas con $exists comprueban la presencia o ausencia de un campo; un campo ausente y un campo con valor null son diferentes y pueden distinguirse combinando $exists: true con $ne: null; $type filtra por nombre de tipo BSON (string, number, date, array, etc.) y es esencial para las auditorías de calidad de datos en colecciones con esquemas flexibles; y los índices dispersos permiten admitir de forma eficiente consultas $exists: true sobre campos opcionales, ya que solo indexan los documentos que tienen el campo. A continuación exploraremos las consultas con expresiones regulares y la coincidencia de patrones para realizar búsquedas de texto flexibles.

Gratis para empezar

Aprende JavaScript con un tutor de IA — gratis

Escribe y ejecuta código real en tu navegador, obtén ayuda instantánea de un tutor de IA disponible 24/7 y continúa donde lo dejaste en la web o en la aplicación.

Cursos
30
Lecciones
120

Preguntas frecuentes

¿La lección «Operadores de elementos y comprobaciones de tipos» es gratis?

Sí — el texto completo de «Operadores de elementos y comprobaciones de tipos» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de MongoDB Academy, actualiza a CoddyKit PRO. El curso de MongoDB Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Operadores de elementos y comprobaciones de tipos»?

Consultará la existencia o el tipo de un campo mediante $exists y $type para gestionar datos opcionales o de tipos mixtos. Practicas MongoDB Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar MongoDB Academy?

No se requiere experiencia previa. MongoDB Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Operadores de elementos y comprobaciones de tipos»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de MongoDB Academy?

Sí. Cada lección de MongoDB Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Operadores de comparación: $eq, $gt, $lt, $in
  2. Operadores lógicos: $and, $or, $nor, $not
  3. Operadores de elementos y comprobaciones de tipos
  4. Consultas con regex y coincidencia de patrones
← Volver a MongoDB Academy