En cualquier negocio, los datos son tu mayor activo. Al analizar los datos, puedes tomar decisiones sobre las tendencias de los clientes y la predicción de su comportamiento. Esto aumenta la rentabilidad del negocio y la eficacia en la toma de decisiones.

Sin un software de base de datos, una tarea sencilla como encontrar la media de todos los valores de un sistema lleno de registros sería tediosa. Por suerte, las bases de datos han facilitado y agilizado el análisis de los datos con funciones y operadores.

Este artículo arrojará algo de luz sobre los operadores utilizados en el software de base de datos MongoDB.

¿Qué Son los Operadores de MongoDB?

MongoDB es un software de base de datos NoSQL que gestiona información orientada a documentos.

Una de las características clave de MongoDB es su velocidad. Para devolver las consultas más rápidamente, MongoDB puede utilizar operadores para realizar funciones específicas.

Los operadores son símbolos especiales que ayudan a los compiladores a realizar tareas matemáticas o lógicas. MongoDB ofrece varios tipos de operadores para interactuar con la base de datos.

Tipos de Operadores de MongoDB

Hay nueve tipos de operadores, cada uno de los cuales recibe el nombre de su función. Por ejemplo, los operadores lógicos utilizan operaciones lógicas. Para ejecutarlos, tienes que utilizar una palabra clave específica y seguir la sintaxis. Sin embargo, ¡son bastante fáciles de seguir!

Al final del artículo, podrás aprender lo básico de cada operador y sus funciones.

Operadores lógicos

Los operadores lógicos se utilizan a menudo para filtrar datos en función de las condiciones dadas. También permiten la evaluación de muchas condiciones, de las que hablaremos con más detalle.

A continuación te presentamos algunos operadores lógicos que puedes utilizar:

$and

Una condición «and» realiza una operación lógica «and» en una matriz de dos o más expresiones. Selecciona los documentos en los que se cumplen todas las condiciones de las expresiones.

Esta es la sintaxis estándar de la expresión $and:

{ $and: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }
db.inventory.find( { $and: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

$or

Una condición «or» realiza una operación lógica «or» en una matriz de dos o más expresiones. Selecciona los documentos en los que al menos una de las expresiones es verdadera.

Esta es la sintaxis estándar de la expresión $or:

{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }.

Por ejemplo, si queremos seleccionar los documentos en los que el precio es de 10 dólares o la cantidad es inferior a 15, podemos introducir la siguiente consulta

db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

No tenemos que limitar la expresión a dos criterios, podemos añadir más. Por ejemplo, la siguiente consulta selecciona aquellos documentos cuyo precio es igual a 10 dólares, la cantidad es inferior a 15, o la etiqueta es estacionaria:

db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 }, { tag: "stationary" }] } )

Al ejecutar estas cláusulas, MongoDB realiza una exploración de la colección o una exploración del índice. Si todos los índices admiten las cláusulas, entonces MongoDB utiliza los índices para comprobar una expresión $or. En caso contrario, utiliza un escaneo de la colección en su lugar.

Pero si quieres comprobar los criterios en el mismo campo, es posible que quieras utilizar el operador $in en lugar del operador $or. Por ejemplo, si quieres una colección de documentos en la que la cantidad sea 10 o 20, tendrás que ejecutar la siguiente consulta $in en su lugar:

db.inventory.find ( { quantity: { $in: [20, 50] } } )

Más adelante hablaremos del operador $in.

$nor

Este operador realiza una operación lógica «nor» en una matriz utilizando una o varias expresiones. A continuación, selecciona los documentos que no cumplen las expresiones de la consulta. En términos más sencillos, hace lo contrario de la condición $or.

Esta es la sintaxis general:

{ $nor: [ { <expression1> }, { <expression2> }, ...  { <expressionN> } ] }

Consideremos la siguiente consulta:

db.inventory.find( { $nor: [ { price: 3.99 }, { sale: true } ]  } )

Esta consulta selecciona los documentos que contienen:

  • un valor del campo de precio que no sea igual a 3,99 dólares y un valor de venta que no sea verdadero; o
  • un valor de campo de precio no igual a 3,99 dólares, y un campo de venta vacío o ausente; o
  • no hay campo de precio y el campo de venta no es verdadero; o
  • ni campo de precio ni campo de venta poblados o presentes

$not

Este operador realiza una operación lógica de «not» en una matriz para la expresión especificada. A continuación, selecciona los documentos que no coinciden con las expresiones de la consulta. Esto incluye los documentos que no contienen el campo.

Esta es la sintaxis general:

{ field: { $not: { <operator-expression> } } }

Por ejemplo, toma la siguiente consulta:

db.inventory.find( { price: { $not: { $lt: 3.99 } } } )

Esta consulta seleccionaría los documentos que contengan

  • un campo de precio cuyo valor es mayor o igual a 3,99 dólares; y
  • un campo de precio no está poblado o no existe.

Operadores de comparación

Los operadores de comparación pueden utilizarse para comparar valores en uno o más documentos.

A continuación se muestra un código de ejemplo de una simple colección de inventario para una tienda de supermercado:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] },
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] },
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] },
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] },
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] },
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Utilizaremos este ejemplo mientras detallamos cada operador de comparación a continuación.

Igual a ($eq)

Este operador coincide con los valores que son iguales al valor dado:

{ <field>: { $eq: <value> } }

Por ejemplo, si queremos recuperar un documento concreto de la colección de inventario que tenga el valor exacto de cantidad «20», introduciríamos el siguiente comando:

db.inventory.find( { qty: { $eq: 20 } } )

La consulta devolvería lo siguiente:

{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, 
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Mayor que ($gt)

Este operador coincide si los valores son mayores que el valor dado:

{ field: { $gt: value } }

En este ejemplo, recuperamos los documentos en los que la cantidad es mayor que 15:

db.inventory.find({"qty": { $gt: 15}})

La consulta devolvería lo siguiente:

{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Menor que ($lt)

Este operador coincide si los valores son menores que el valor proporcionado:

{ field: { $lt: value } }

Busquemos los documentos con una cantidad inferior a 25:

db.inventory.find({"qty": { $lt: 25}})

La consulta devolvería lo siguiente:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Mayor o igual que ($gte)

Este operador coincide cuando los valores son mayores o iguales que el valor dado:

{ field: { $gte: value } }

En este ejemplo, recuperamos los documentos cuya cantidad es mayor o igual a 25:

db.inventory.find({"qty": { $gte: 25}})

Esta consulta devolvería lo siguiente:

{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

Menor o igual que ($lte)

Este operador sólo coincide si los valores son menores o iguales que el valor dado:

{ field: { $lte: value } }

Busquemos los documentos con una cantidad menor o igual a 25.

db.inventory.find({"qty": { $lte: 25}})

Podemos esperar que esta consulta devuelva lo siguiente:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

En ($en)

Este operador devuelve los documentos que coinciden con los valores especificados:

{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }

El valor de un campo es igual a cualquier valor de la matriz especificada. Para recuperar los documentos con los valores «30» y «15» en la colección de inventario, por ejemplo, harías lo siguiente:

db.inventory.find({ "qty": { $in: [30, 15]}})

El resultado sería:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

No en ($nin)

Este operador devuelve los documentos que no coinciden con los valores dados. Esta es la sintaxis básica del operador $nin:

{ field: { $nin: [ <value1>, <value2> ... <valueN> ]

$nin selecciona los documentos donde:

  • el valor del campo no está en la matriz especificada; o
  • el campo no existe.

Si el campo contiene matrices, seleccionará las matrices en las que no esté presente ningún elemento especificado en la sección de valores. Por ejemplo, queremos seleccionar aquellos documentos en los que la cantidad no sea ni 20 ni 15.

Además, también coincide con los documentos que no tienen un campo de cantidad:

db.inventory.find({ "qty": { $nin: [ 20, 15 ]}})

El resultado sería:

{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

No es igual ($ne)

El operador $ne devuelve los documentos en los que el valor especificado no es igual:

{ $ne: value } }

Por ejemplo, digamos que queremos seleccionar todos los documentos en los que la cantidad no es igual a 20:

db.inventory.find( { qty: { $ne: 20 } } )

El resultado sería:

{ _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }
{ _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }
{ _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
{ _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Del resultado anterior, podemos ver que la consulta seleccionará los documentos que no tengan un campo de cantidad.

Operadores de elementos

Los operadores de consulta de elementos pueden identificar los documentos utilizando los campos del documento. Los operadores de elementos consisten en $exist y $type.

$exists

Este operador coincide con los documentos que tienen un campo especificado. Este operador tiene un valor booleano que puede ser true o false.

Si se especifica que es true, coincide con los documentos que contienen ese campo, incluidos los documentos en los que el valor del campo es nulo. Si <boolean> es false, la consulta sólo devuelve los documentos que no contienen el campo.

Esta es la sintaxis estándar:

{ field: { $exists: <boolean> } } )

Tomemos un ejemplo en el que tenemos una colección de datos para un array llamado «bagofmarbles», en el que cada bolsa contiene canicas de diferentes colores:

{ red: 5, green: 5, blue: null }
{ red: 3, green: null, blue: 8 }
{ red: null, green: 3, blue: 9 }
{ red: 1, green: 2, blue: 3 }
{ red: 2, blue: 5 }
{ red: 3, green: 2 }
{ red: 4 }
{ green: 2, blue: 4 }
{ green: 2 }
{ blue: 6 }

Digamos que queremos una consulta que nos devuelva sólo las bolsas en las que existen canicas rojas. Esto significa que tendríamos que introducir el valor booleano como true. Echemos un vistazo:

db.bagofmarbles.find( { red: { $exists: true } } )

Los resultados consistirían en aquellos documentos que contengan el campo «rojo», aunque el valor fuera null. Sin embargo, no consistirían en los documentos en los que el campo «rojo» ni siquiera existiera:

{ red: 5, green: 5, blue: null }
{ red: 3, green: null, blue: 8 }
{ red: null, green: 3, blue: 9 }
{ red: 1, green: 2, blue: 3 }
{ red: 2, blue: 5 }
{ red: 3, green: 2 }
{ red: 4 }

Si sólo quisiéramos las bolsas en las que las canicas rojas ni siquiera existen como campo, podemos introducir la siguiente consulta:

db.bagofmarbles.find( { red: { $exists: false} )

Los resultados consistirían en aquellos documentos que no contienen el campo «rojo»:

{ green: 2, blue: 4 }
{ green: 2 }
{ blue: 6 }

$type

Este operador hace coincidir los documentos según el tipo de campo especificado. Es útil cuando tienes datos muy desestructurados, o cuando los tipos de datos no son predecibles. Estos tipos de campo son tipos BSON especificados y pueden definirse por número de tipo o por alias.

Esta es la sintaxis general de $type:

{ field: { $type: <BSON type> } }

Supongamos que tenemos una libreta de direcciones que contiene los siguientes documentos

db={
  addressBook: [
    {
      "_id": 1,
      address: "2100 Jupiter Spot",
      zipCode: "9036325"
    },
    {
      "_id": 2,
      address: "25 Moon Place",
      zipCode: 26237
    },
    {
      "_id": 3,
      address: "2324 Neptune Ring",
      zipCode: NumberLong(77622222)
    },
    {
      "_id": 4,
      address: "33 Saturns Moon",
      zipCode: NumberInt(117)
    },
    {
      "_id": 5,
      address: "1044 Venus Lane",
      zipCode: [
        "99883637232",
        "73488976234"
      ]
    }
  ]
}

Al observar los documentos anteriores, el código postal tiene diferentes tipos de datos. Esto incluye valores largos, dobles, enteros y de cadena.

Si sólo queremos los documentos que tienen un tipo de datos específico como código postal – tomemos la cadena para este caso – tendríamos que introducir la siguiente consulta en el compilador:

db.addressBook.find({
  "zipCode": {
    $type: "string"
  }
})

Esto nos devolvería los siguientes documentos:

[
  {
    "_id": 1,
    "address": "2100 Jupiter Spot",
    "zipCode": "9036325"
  },
  {
    "_id": 5,
    "address": "1044 Venus Lane",
    "zipCode": [
      "99883637232",
      "73488976234"
    ]
  }
]

Además, existe un tipo «número», que incluye todos los valores largos, enteros o dobles como una matriz que contiene un elemento de los tipos especificados:

db.addressBook.find( { "zipCode" : { $type : "number" } } )

Resultado:

[
{
      "_id": 2,
      address: "25 Moon Place",
      zipCode: 26237
    },
    {
      "_id": 3,
      address: "2324 Neptune Ring",
      zipCode: NumberLong(77622222)
    },
    {
      "_id": 4,
      address: "33 Saturns Moon",
      zipCode: NumberInt(117)
    }
]

Si los documentos tienen un tipo de campo de matriz, el operador $type devuelve los documentos en los que al menos un elemento de la matriz coincide con el tipo pasado al operador.

Operadores de matrices

MongoDB también dispone de operadores de matrices o arrays, para consultar documentos que contienen matrices.

Hay tres operadores principales: $all, $elemMatch y $size. A continuación hablaremos de cada uno de ellos en detalle.

$all

El operador $all elige los documentos en los que el valor de un campo es una matriz que contiene los elementos especificados:

{ : { $all: [ <value1> , <value2> ... ] } }

Por ejemplo, supongamos que tenemos una colección de documentos de una tienda de ropa, con lo siguiente en el inventario.

{
   _id: ObjectId("5234cc89687ea597eabee675"),
   code: "shirt",
   tags: [ "sale", "shirt", "button", "y2k", "casual" ],
   qty: [
          { size: "S", num: 10, color: "blue" },
          { size: "M", num: 45, color: "blue" },
          { size: "L", num: 100, color: "green" }
        ]
},

{
   _id: ObjectId("5234cc8a687ea597eabee676"),
   code: "pant",
   tags: [ "y2k", "trendy", "shine" ],
   qty: [
          { size: "6", num: 100, color: "green" },
          { size: "6", num: 50, color: "blue" },
          { size: "8", num: 100, color: "brown" }
        ]
},

{
   _id: ObjectId("5234ccb7687ea597eabee677"),
   code: "pant2",
   tags: [ "trendy", "shine" ],
   qty: [
          { size: "S", num: 10, color: "blue" },
          { size: "M", num: 100, color: "blue" },
          { size: "L", num: 100, color: "green" }
        ]
},

{
   _id: ObjectId("52350353b2eff1353b349de9"),
   code: "shirt2",
   tags: [ "y2k", "trendy" ],
   qty: [
          { size: "M", num: 100, color: "green" }
        ]
}

Querríamos recuperar cualquier documento (en este caso, la ropa) del inventario que esté vinculado con las etiquetas «trendy» y «y2k». La siguiente consulta utiliza el operador $all, donde el valor del campo etiquetas es una matriz cuyos elementos incluyen «y2k» y «trendy»:

db.inventory.find( { tags: { $all: [ "y2k", "trendy" ] } } )

La consulta anterior devuelve lo siguiente:

{
   _id: ObjectId("5234cc8a687ea597eabee676"),
   code: "pant",
   tags: [ "y2k", "trendy", "shine" ],
   qty: [
          { size: "6", num: 100, color: "green" },
          { size: "6", num: 50, color: "blue" },
          { size: "8", num: 100, color: "brown" }
        ]
}

{
   _id: ObjectId("52350353b2eff1353b349de9"),
   code: "shirt2",
   tags: [ "y2k", "trendy" ],
   qty: [
          { size: "M", num: 100, color: "green" }
        ]
}

En el ejemplo anterior, también encontramos que el operador $all simplemente realiza la misma función que la operación $and.

Como alternativa, podríamos utilizar la siguiente consulta, que daría un resultado similar al anterior:

db.inventory.find({
  $and: [
    {
      tags: "y2k"
    },
    {
      tags: "trendy"
    }
  ]
})

$elemMatch

El operador $elemMatch coincide con los documentos que contienen un campo de matriz con al menos un elemento que coincide con todos los criterios de consulta especificados:

{ : { $elemMatch: { <query1>, <query2>, ... } } }

Aunque podemos utilizar operadores de comparación como $lte y $gte, si sólo especificamos una única condición de consulta dentro de $elemMatch, y no utilizamos los operadores $not o $ne, se puede omitir la utilización de $elemMatch, ya que esencialmente estaría realizando la misma función.

Hay algunas cosas más que hay que tener en cuenta al utilizar este operador, principalmente:

  • No puedes especificar una expresión $where en una operación $elemMatch.
  • No puedes especificar una expresión de consulta $text en una operación $elemMatch.

Por ejemplo, tenemos los siguientes documentos en la colección de resultados de estudiantes:

{ _id: 1, results: [ 92, 89, 98 ] }
{ _id: 2, results: [ 85, 99, 99 ] }

La siguiente consulta sólo coincide con los documentos en los que la matriz de resultados contiene al menos un elemento que es mayor o igual que 90 y es menor que 95:

db.studentresults.find(  { results: { $elemMatch: { $gte: 90, $lt: 95 } } })

Nuestra consulta devuelve el siguiente documento, ya que el elemento 92 es a la vez mayor o igual que 90 y menor que 95:

{ "_id" : 1, "results" :[ 92, 89, 98 ] }

$size

El operador $size devuelve aquellos documentos en los que el tamaño de la matriz coincide con el número de elementos especificado en el argumento:

{ field: { $size: value } }

Aquí tienes un ejemplo:

db.collection.find( { field: { $size: 2 } });

Esto devolvería todos los documentos de la colección especificada en la que el campo es una matriz con 2 elementos: { field: [ orange, apple] } y { field: [ blue, red] }, pero no { field: blue} ni { field: [ raspberry, lemon, grapefruit ] }.

Sin embargo, aunque podemos introducir el valor concreto como tamaño, no podemos especificar rangos de valores como tamaño.

Operadores geoespaciales

MongoDB te permite almacenar datos geoespaciales en forma de tipos GeoJSON. GeoJSON es un formato de estándar abierto basado en la notación de objetos de JavaScript que puede representar características geográficas y admitir atributos no espaciales. Hay dos tipos de operadores geoespaciales de los que hablaremos en este artículo: los especificadores de geometría y los selectores de consulta.

$geometry

Este operador menciona la geometría GeoJSON para su uso con los siguientes operadores de consulta geoespacial: $geoIntersects, $geoWithin,$nearSphere, y $near. $geometry aprovecha EPSG:4326 como sistema de referencia de coordenadas (CRS) por defecto.

Para mencionar objetos GeoJSON con el CRS por defecto, puedes aprovechar el siguiente fragmento para $geometry:

$geometry: {
   type: "<GeoJSON object type>",
   coordinates: [ <coordinates> ]
}

Para mencionar un polígono GeoJSON de un solo anillo con un CRS de MongoDB adaptado, puedes utilizar el siguiente fragmento (sólo puedes utilizarlo para $geoWithin y $geoIntersects):

$geometry: {
   type: "Polygon",
   coordinates: [ <coordinates> ],
   crs: {
      type: "name",
      properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" }
   }
}

$polygon

El operador $polygon puede utilizarse para especificar un polígono para una consulta geoespacial $geoWithin sobre pares de coordenadas heredados. Esta consulta devolverá los pares que estén dentro de los límites del polígono. Sin embargo, $polygon no consultará ningún objeto GeoJSON. Para definir un polígono, debes especificar una matriz de puntos de coordenadas como se indica a continuación:

{
   : {
      $geoWithin: {
         $polygon: [ [ <x1> , <y1> ], [ <x2> , <y2> ], [ <x3> , <y3> ], ... ]
      }
   }
}

Aquí, el último punto está implícitamente conectado al primero. Puedes mencionar tantos puntos o lados como quieras.

Por ejemplo, la siguiente consulta devolverá todos los documentos que tienen coordenadas que existen dentro del polígono definido por [0,0], [1,5] y [3,3]:

db.places.find(
  {
     loc: {
       $geoWithin: { $polygon: [ [ 0 , 0 ], [ 1 , 5 ], [ 3 , 3 ] ] }
     }
  }
)

$geoWithin

Este operador se puede utilizar para elegir documentos con datos geoespaciales que estén completamente contenidos en una forma específica. La forma especificada puede ser un multipolígono GeoJSON, un polígono GeoJSON (de anillos múltiples o de anillos simples), o una forma que puede ser definida por pares de coordenadas heredadas.

El operador $geoWithin aprovechará el operador $geometry para mencionar el objeto GeoJSON.

Para mencionar los multipolígonos o polígonos GeoJSON a través del Sistema de Referencia de Coordenadas (SRC) por defecto, puedes utilizar la sintaxis mencionada a continuación:

{
   : {
      $geoWithin: {
         $geometry: {
            type: <"Polygon" or "MultiPolygon"> ,
            coordinates: [ <coordinates> ]
         }
      }
   }
}

Para las consultas de $geoWithin que mencionan las geometrías GeoJSON con áreas mayores que un solo hemisferio, el uso del CRS por defecto llevaría a consultas de las geometrías complementarias.

Para mencionar un polígono GeoJSON de un solo anillo con un CRS personalizado de MongoDB, puedes aprovechar el prototipo mencionado a continuación en la expresión $geometry:

{
   : {
      $geoWithin: {
         $geometry: {
           type: "Polygon" ,
           coordinates: [ <coordinates> ],
           crs: {
              type: "name",
              properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" }
           }
         }
      }
   }
}

El siguiente ejemplo recoge todos los datos de localización que existen completamente dentro de un polígono GeoJSON, siendo el área del polígono menor que el área de un solo hemisferio:

db.places.find(
   {
     loc: {
       $geoWithin: {
          $geometry: {
             type : "Polygon" ,
             coordinates: [ [ [ 0, 0 ], [ 3, 6 ], [ 6, 1 ], [ 0, 0 ] ] ]
          }
       }
     }
   }
)

$box

Puedes utilizar $box para especificar un rectángulo para que una consulta geoespacial $geoWithin te proporcione los documentos que están dentro de los límites del rectángulo, según sus datos de localización basados en puntos. Cuando utilices $geoWithin con el $box, obtendrás documentos basados en las coordenadas de la consulta. En este escenario, $geoWithin no consultará ninguna forma GeoJSON.

Para aprovechar el operador $box, tienes que mencionar las esquinas superior derecha e inferior izquierda del rectángulo en un objeto array:

{ <location field> : { $geoWithin: { $box: [ [ <bottom left coordinates> ],
 [ <upper right coordinates> ] ] } } }

La consulta mencionada calculará la distancia utilizando la geometría planar (plana). La siguiente consulta devolverá todos los documentos que estén dentro de la caja que tenga puntos en: [0,0], [0,30], [30,0], [30,30]:

db.places.find ( { 
 loc: { $geoWithin: { $box: [ [ 0,0 ], [ 30,30 ] ] } }
} )

$nearSphere

Puedes utilizar $nearSphere para mencionar un punto para el que una consulta geoespacial devuelva los documentos de más cercano a más lejano.

MongoDB utiliza la geometría esférica para calcular las distancias para $nearSphere. Necesitará un índice geoespacial como el siguiente:

  1. índice 2d para datos de localización descritos como pares de coordenadas heredados. Para aprovechar un índice 2d en puntos GeoJSON, debes generar el índice en el campo de coordenadas del objeto GeoJSON.
  2. índice 2dsphere para datos de localización descritos como puntos GeoJSON.

Para mencionar un punto GeoJSON, puedes aprovechar la siguiente sintaxis:

{
  $nearSphere: {
     $geometry: {
        type : "Point",
        coordinates : [ <longitude>, <latitude> ]
     },
     $minDistance: <distance in meters>,
     $maxDistance: <distance in meters> 
  }
}

Aquí, $minDistance y $maxDistance son opcionales. $minDistance puede limitar los resultados a aquellos documentos que estén al menos a la distancia especificada del centro. Puedes utilizar $maxDistance para cualquiera de los dos índices.

Ahora, considera una colección de «lugares» que consiste en documentos con un campo de ubicación que tiene un índice 2dsphere. El siguiente ejemplo devolvería los puntos cuya ubicación está a un mínimo de 2.000 metros y un máximo de 6.000 metros del punto que elijas, ordenados de más cercano a más lejano:

db.places.find(
   {
     location: {
        $nearSphere: {
           $geometry: {
              type : "Point",
              coordinates : [ -43.9532, 50.32 ]
           },
           $minDistance: 2000,
           $maxDistance: 6000
        }
     }
   }
)

$geoIntersects

El operador $geoIntersects te permite seleccionar los documentos cuyos datos geoespaciales se intersectan con un objeto GeoJSON concreto (es decir, cuando la convergencia del objeto especificado y los datos no está vacía). Aprovecha el operador $geometry para especificar el objeto GeoJSON.

Para mencionar los multipolígonos o polígonos GeoJSON a través del sistema de referencia de coordenadas (CRS) por defecto, puedes utilizar la siguiente sintaxis:

{ <location field>: {
     $geoIntersects: {
        $geometry: {
           type: "<GeoJSON object type>" ,
           coordinates: [ <coordinates> ]
        }
     }
  }
}

La siguiente instancia utilizará $geoIntersects para recoger todos los datos loc que se cruzan con el polígono descrito por la matriz de coordenadas:

db.places.find(
   {
     loc: {
       $geoIntersects: {
          $geometry: {
             type: "Polygon" ,
             coordinates: [
               [ [ 0, 0 ], [ 2, 6 ], [ 4, 1 ], [ 0, 0 ] ]
             ]
          }
       }
     }
   }
)

$center

El operador $center menciona un círculo para una consulta $geoWithin que devuelve los pares de coordenadas heredadas que están dentro de los límites del círculo.

$center no devuelve objetos GeoJSON. Para aprovechar el operador $center, tienes que especificar un array que contenga:

  1. El radio del círculo, medido en las unidades utilizadas por el sistema de coordenadas.
  2. Las coordenadas de la cuadrícula del punto central del círculo.
{
  <location field> : {
      $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] }
   }
}

El ejemplo mencionado a continuación devolverá todos los documentos que tengan coordenadas que se encuentren dentro del círculo centrado en [2,3] y con un radio de 40:

db.places.find(
   { loc: { $geoWithin: { $center: [ [2, 3], 40 ] } } }
)

Operadores de proyección

Puedes utilizar operadores de proyección para mencionar los campos devueltos por una operación. Los operadores de proyección de MongoDB permiten utilizar la función find() con argumentos de filtrado de datos. Esto ayuda a los usuarios a extraer sólo los campos de datos necesarios de un documento. Por tanto, permite proyectar datos transparentes y concisos sin afectar al rendimiento general de la base de datos.

$elemMatch (proyección)

El operador $elemMatch se encarga de limitar el contenido de un campo de los resultados de la consulta para que sólo contenga el primer elemento que coincida con la condición $elemMatch.

Debes tener en cuenta algunas cosas antes de utilizar $elemMatch:

  • A partir de MongoDB 4.4, independientemente del orden de los campos en el documento, la proyección $elemMatch de un campo existente devuelve el campo tras la inclusión de otros campos existentes.
  • Tanto el operador $elemMatch como el $ proyectan el primer elemento coincidente de una matriz en función de una condición especificada. El operador $ proyectaría el primer elemento coincidente de la matriz de cada documento de una colección basándose en alguna condición de la sentencia de consulta, mientras que el operador de proyección $elemMatch toma un argumento de condición explícito. Esto te permite proyectar en base a una condición no presente en la consulta, o si necesitas proyectar en base a varios campos de los documentos incrustados en el array.

También debes tener en cuenta las siguientes restricciones antes de utilizar el operador $elemMatch en tus datos:

  • No puedes mencionar una expresión de consulta $text dentro de un operador $elemMatch.
  • db.collection.find() las operaciones sobre vistas no admiten el operador de proyección $elemMatch.

El siguiente ejemplo sobre el operador de proyección $elemMatch supone una colección schools con los siguientes documentos:

{
 _id: 1,
 zipcode: "63108",
 students: [
              { name: "mark", school: 102, age: 9 },
              { name: "geoff", school: 101, age: 13 },
              { name: "frank", school: 104, age: 12 }
           ]
}
{
 _id: 2,
 zipcode: "63110",
 students: [
              { name: "harry", school: 103, age: 14 },
              { name: "george", school: 103, age: 7 },
           ]
}
{
 _id: 3,
 zipcode: "63108",
 students: [
              { name: "harry", school: 103, age: 14 },
              { name: "george", school: 103, age: 7 },
           ]
}
{
 _id: 4,
 zipcode: "63110",
 students: [
              { name: "jim", school: 103, age: 9 },
              { name: "michael", school: 103, age: 12 },
           ]
}

En este caso, la operación find() busca todos los documentos en los que el valor del campo código postal es 63110. La proyección $elemMatch devolvería sólo el primer elemento coincidente de la matriz students en el que el campo school tenga el valor 103:

db.schools.find( { zipcode: "63110" },
                 { students: { $elemMatch: { school: 103 } } } )

Este es el resultado:

{ "_id" : 2, "students" : [ { "name" : "harry", "school" : 103, "age" : 14 } ] }
{ "_id" : 4, "students" : [ { "name" : "jim", "school" : 103, "age" : 9 } ] }

$slice (proyección)

El operador de proyección $slice puede utilizarse para especificar el número de elementos de una matriz que se devolverán en el resultado de la consulta:

db.collection.find(
   <query> ,
   { <arrayField> : { $slice: <number> } }
);

También se puede expresar de esta manera:

db.collection.find(
  <query> ,
   { <arrayField> : { $slice: [ <number> , <number> ] } }
);

Para demostrarlo, puedes crear una colección de tuits de ejemplo con los siguientes documentos:

db.posts.insertMany([
   {
     _id: 1,
     title: "Nuts are not blueberries.",
     comments: [ { comment: "0. true" }, { comment: "1. blueberries aren't nuts."} ]
   },
   {
     _id: 2,
     title: "Coffee please.",
     comments: [ { comment: "0. Indubitably" }, { comment: "1. Cuppa tea please" }, { comment: "2. frappucino" }, { comment: "3. Mocha latte" }, { comment: "4. whatever" } ]
   }
])

La siguiente operación utilizaría el operador de proyección $slice en la matriz de tweets para devolver la matriz con sus dos primeros elementos. Si una matriz contiene menos de dos elementos, se devuelven todos los elementos de la matriz:

db.posts.find( {}, { comments: { $slice: 2 } } )

Esta operación devolvería los siguientes documentos:

{
   "_id" : 1,
   "title" : "Nuts are not blueberries.",
   "comments" : [ { "comment" : "0. true" }, { "comment" : "1. blueberries aren't nuts." } ]
}
{
   "_id" : 2,
   "title" : "Coffee please.",
   "comments" : [ { "comment" : "0. Indubitably" }, { "comment" : "1. Cuppa tea please" } ]
}

$ (proyección)

El operador posicional $ limita el contenido de un array para devolver el primer elemento que coincida con la condición de consulta de ese array. Puedes utilizar $ en el documento de proyección del método find() o del método findOne() cuando sólo necesites un elemento concreto de la matriz en los documentos elegidos.

Este es el aspecto de la sintaxis del operador $:

db.collection.find( { <array>: <condition> ... },
                    { "<array>.$": 1 } )
db.collection.find( { <array.field>: <condition> ...},
                    { "<array>.$": 1 } )

En este ejemplo, la colección students está formada por los siguientes documentos:

{ "_id" : 1, "semester" : 2, "grades" : [ 75, 67, 93 ] }
{ "_id" : 2, "semester" : 2, "grades" : [ 60, 68, 72 ] }
{ "_id" : 3, "semester" : 2, "grades" : [ 95, 82, 67 ] }
{ "_id" : 4, "semester" : 3, "grades" : [ 89, 95, 70 ] }
{ "_id" : 5, "semester" : 3, "grades" : [ 68, 98, 82 ] }
{ "_id" : 6, "semester" : 3, "grades" : [ 65, 70, 76 ] }

En la siguiente consulta, la proyección { "grades.$": 1 } devuelve sólo el primer elemento mayor o igual que 89 para el campo grades:

db.students.find( { semester: 2, grades: { $gte: 89 } },
                  { "grades.$": 1 } )

Esta operación devuelve los siguientes documentos:

{"_id": 1, "grades": [93] }

Operadores de evaluación

Puedes aprovechar los operadores de evaluación de MongoDB para calibrar la estructura general de datos o un campo individual dentro de un documento.

Veamos algunos operadores de evaluación comunes de MongoDB.

$mod

Puedes utilizar este operador para hacer coincidir los documentos en los que el valor de un campo especificado es igual al resto después de ser dividido por un valor especificado:

{ field: { $mod: [ divisor, remainder ] } }

Supongamos que tienes una tabla de coches de diferentes marcas que tienes en tu sala de exposiciones. La siguiente consulta te daría todas las marcas de coches cuyos números de stock sean múltiplos de 250.

db.cars.find ( { qty: { $mod: [ 250,0 ] } } )

$jsonSchema

La página $jsonSchema te permite hacer coincidir los documentos que coinciden con el esquema JSON especificado. La implementación de MongoDB del esquema JSON incluye la adición de la palabra clave bsonType, que te permite utilizar todos los tipos BSON dentro del operador $jsonSchema.

bsonType puede aceptar los mismos alias de cadena que usarías para el operador type. Este es el aspecto que tendría la sintaxis de $jsonSchema:

{ $jsonSchema: <JSON Schema object> }

Aquí, el objeto del esquema JSON está formateado según el borrador 4 del estándar JSON:

{ <keyword1>: <value1>, ... }

Aquí tienes un ejemplo para demostrar cómo funciona $jsonSchema:

{ $jsonSchema: {
     required: [ "name", "major", "gpa", "address" ],
     properties: {
        name: {
           bsonType: "string",
           description: "must be a string and is required"
        },
        address: {
           bsonType: "object",
           required: [ "zipcode" ],
           properties: {
               "street": { bsonType: "string" },
               "zipcode": { bsonType: "string" }
           }
        }
     }
  }
}

También puedes utilizar $jsonSchema en un validador de documentos para hacer cumplir el esquema especificado en las operaciones de actualización e inserción:

db.createCollection(<collection> , { validator: { $jsonSchema: <schema> } } )
db.runCommand( { collMod: <collection>, validator:{ $jsonSchema: <schema> } } )

Ten en cuenta que hay varias cosas que no admite el operador $jsonSchema:

  1. El tipo entero. Tienes que aprovechar el tipo BSON long o int con la palabra clave bsonType.
  2. Palabras clave desconocidas.
  3. Las propiedades de enlace y la hipermedia del esquema JSON, junto con el uso de referencias JSON y punteros JSON.

$text

El operador $text buscaría un texto dentro del contenido del campo especificado, indexado con un índice de texto:

{  
  $text:  
    {  
      $search: <string>,  
      $language: <string>,  
      $caseSensitive: <boolean>,  
      $diacriticSensitive: <boolean>   
    }  
}

En este caso, el siguiente fragmento de código examinará la tabla para filtrar los coches que tengan el texto «Porsche»:

db.cars.find( { $text: { $search: "Porsche" } } )

$regex

El operador $regex ofrece la posibilidad de utilizar expresiones regulares para hacer coincidir cadenas con patrones en las consultas. MongoDB aprovecha las expresiones regulares que son compatibles con Perl:

{<field> : /pattern/ <options>}

El siguiente ejemplo ayudaría a filtrar todos los coches que tengan la cadena «$78900» presente en ellos:

db.cars.find( { price: { $regex: /$78900/ } } )

$expr

El operador $expr te permite aprovechar las expresiones de agregación dentro del lenguaje de consulta:

{ $expr: { <expression> } }

También puedes utilizar $expr para construir expresiones de consulta que comparen campos del mismo documento en una etapa $match. Si la etapa $match forma parte de una etapa $lookup, $expr puede comparar campos con la ayuda de variables let.

$where

Puedes aprovechar el operador $where para pasar una cadena que contenga una función completa de JavaScript o una expresión de JavaScript al sistema de consulta. El operador $where proporciona una mayor flexibilidad, pero necesita que la base de datos procese la función o expresión JavaScript para cada documento de la colección. Puedes hacer referencia a este documento en la función o expresión de JavaScript utilizando obj o this.

Aquí tienes un ejemplo de la sintaxis:

{ $where: <string|JavaScript Code> }

Hay algunas consideraciones clave que debes tener en cuenta antes de sumergirnos en un ejemplo al utilizar el operador $where:

  • Sólo debes utilizar el operador de consulta $where a documentos de nivel superior. El operador de consulta $where no funcionará en un documento anidado, como en una consulta $elemMatch.
  • En general, debes utilizar $where sólo cuando no puedas expresar tu consulta mediante otro operador. Si tienes que utilizar $where, asegúrate de incluir al menos otro operador de consulta estándar para filtrar el conjunto de resultados. El uso de $where de forma independiente requiere una exploración de la colección para su correcta ejecución.

He aquí un ejemplo para ilustrar esto:

db.cars.find( { $where: function() {  
   return (hex_md5(this.name)== "9a43e617b50cd379dca1bc6e2a8")  
} } );

Operadores Bitwise

Los operadores bit a bit devuelven datos en función de las condiciones de posición de los bits. En pocas palabras, se utilizan para hacer coincidir valores numéricos o binarios en los que cualquier bit de un conjunto de posiciones de bits tiene un valor de 1 o 0.

$bitsAllSet

Este operador coincidirá con todos los documentos en los que todas las posiciones de bits proporcionadas por la consulta estén establecidas (es decir, 1) en el campo:

{ <field> : { $bitsAllSet: <numeric bitmask> } }
{ <field> : { $bitsAllSet: < BinData bitmask> } }
{ <field> : { $bitsAllSet: [ <position1> , <position2> , ... ] } }

El valor del campo debe ser una instancia de BinData o numérico para que $bitsAllSet coincida con el documento actual.

En el siguiente caso, estamos aprovechando una colección con los siguientes documentos:

db.collection.save({ _id: 1, a: 54, binaryValueofA: "00110110" })
db.collection.save({ _id: 2, a: 20, binaryValueofA: "00010100" })
db.collection.save({ _id: 3, a: 20.0, binaryValueofA: "00010100" })
db.collection.save({ _id: 4, a: BinData(0, "Zg=="), binaryValueofA: "01100110" })

La consulta mencionada a continuación utilizará el operador $bitsAllSet para comprobar si el campo a tiene los bits en la posición 1 y en la posición 5, donde el bit menos significativo estaría en la posición 0:

db.collection.find( { a: { $bitsAllSet: [ 1, 5 ] } })

Esta consulta coincidiría con los siguientes documentos:

{ "_id" : 1, "a" : 54, "binaryValueofA" : "00110110" }
{ "_id" : 4, "a" : BinData(0,"Zg=="), "binaryValueofA" : "01100110" }

$bitsAllClear

El operador $bitsAllClear coincidirá con los documentos en los que todas las posiciones de bits proporcionadas por la consulta estén claras o 0:

{ <field> : { $bitsAllClear: <numeric bitmask> } }
{ <field> : { $bitsAllClear: < BinData bitmask> } }
{ <field> : { $bitsAllClear: [ <position1> , <position2> , ... ] } }

Utilizaremos el ejemplo de $bitsAllSet para demostrar el uso de $bitsAllClear. La siguiente consulta utilizaría este operador para comprobar si el campo a tiene los bits libres en las posiciones 1 y 5:

db.collection.find( { a: { $bitsAllClear: [ 1, 5 ] } } )

Esta consulta coincidiría con los siguientes documentos:

{ "_id" : 2, "a" : 20, "binaryValueofA" : "00010100" }
{ "_id" : 3, "a" : 20, "binaryValueofA" : "00010100" }

Meta Operadores

Hay varios modificadores de consulta que te permiten modificar el comportamiento o la respuesta de una consulta en MongoDB. Las interfaces del controlador pueden proporcionar métodos de cursor que los envuelven para su uso.

$hint

MongoDB ha dejado de utilizar $hint desde la versión 3.2. Sin embargo, este operador puede seguir estando disponible para los controladores de MongoDB como Go, Java, Scala, Ruby, Swift, etc. Puede forzar al optimizador de consultas a aprovechar un índice específico para realizar la consulta, que puede mencionarse por documento o por nombre de índice.

También puedes utilizar el operador $hint para probar las estrategias de indexación y el rendimiento de la consulta. Por ejemplo, toma la siguiente operación:

db.users.find().hint( { age: 1 } )

Esta operación devolvería todos los documentos de la colección llamada users aprovechando el índice del campo age.

También puedes mencionar una pista utilizando cualquiera de las siguientes formas:

db.users.find()._addSpecial( "$hint", { age : 1 } )
db.users.find( { $query: {}, $hint: { age : 1 } } )

Si existe un filtro de índice para la forma de la consulta, MongoDB simplemente ignoraría el $hint.

$comment

El operador $comment te permite adjuntar un comentario a una consulta en cualquier contexto en el que pueda aparecer $query. Dado que los comentarios se propagan al registro del perfil, añadir un comentario puede facilitar la interpretación y el seguimiento de tu perfil.

Puedes utilizar $comment de una de estas tres maneras:

db.collection.find( { <query> } )._addSpecial( "$comment", <comment> )
db.collection.find( { <query> } ).comment( <comment> )
db.collection.find( { $query: { <query> }, $comment: <comment> } )

Si quieres adjuntar comentarios a expresiones de consulta en otros contextos, como con db.collection.update(), aprovecha el operador de consulta $comment en lugar del metaoperador.

$max

Puedes mencionar un valor de $max para especificar el límite superior exclusivo de un índice concreto para restringir los resultados de find(). Este operador especificará el límite superior de todas las claves de un orden concreto en el índice.

Mongosh te ofrece el siguiente método envolvente max():

db.collection.find( { <query> } ).max( { field1: <max value> , ... fieldN: <max valueN> } )

También puedes mencionar $max con las dos formas siguientes:

db.collection.find( { <query> } )._addSpecial( "$max", { field1: <max value1> ,
 ... fieldN: <max valueN> } )
db.collection.find( { $query: { <query> }, $max: { field1: <max value1> ,
 ... fieldN: <max valueN> } } )

Por ejemplo, si quieres especificar el límite superior exclusivo, ten en cuenta las siguientes operaciones sobre una colección llamada colección que contiene un índice { age: 1 }:

db.collection.find( { <query> } ).max( { age: 100 } ).hint( { age: 1 } )

Esta operación limitará la consulta a aquellos documentos en los que el campo edad sea inferior a 100 y forzará un plan de consulta que explorará el índice { age: 1 } desde minKey hasta 100.

$explain

Este operador te dará información sobre el plan de consulta. Devuelve un documento que describe los índices y procesos utilizados para devolver la consulta. Esto puede ser útil cuando se trata de optimizar una consulta.

Puedes mencionar el operador $explain en cualquiera de las siguientes formas:

db.collection.find()._addSpecial( "$explain", 1 )
db.collection.find( { $query: {}, $explain: 1 } )

Las Mejores Prácticas para los Operadores de MongoDB

En esta sección, echaremos un vistazo a algunas de las mejores prácticas para utilizar estos operadores de MongoDB.

Incrustación y referenciación

La incrustación es una extensión natural del modelado de datos. Te permite evitar las uniones de aplicaciones, lo que puede reducir las actualizaciones y las consultas.

Puedes incrustar datos con una relación 1:1 dentro de un único documento. Dicho esto, los datos con una relación muchos:1 en la que aparecen «muchos» objetos con sus documentos padre también pueden ser buenos candidatos.

Almacenar este tipo de datos en el mismo documento parece una opción prudente. Sin embargo, la incrustación proporciona un mejor rendimiento para las operaciones de lectura con este tipo de localidad de datos.

Los modelos de datos incrustados también pueden ayudar a los desarrolladores a actualizar los datos asociados en una sola operación de escritura. Esto funciona porque las escrituras de un solo documento son transaccionales.

Deberías considerar el uso de la referenciación para los siguientes escenarios:

  • Cuando se actualiza un segmento del documento y éste se alarga, mientras que el resto del documento permanece estático.
  • Cuando se accede a un documento, pero contiene datos que se utilizan raramente. La incrustación sólo aumentaría los requisitos en memoria, por lo que la referenciación tiene más sentido.
  • Cuando el tamaño del documento supera el límite de documentos de 16 MB de MongoDB. Esto puede ocurrir cuando se modelan relaciones muchos:1 (por ejemplo, empleados:departamento).

Examinar el perfil y los patrones de consulta

Para la mayoría de los desarrolladores, el primer paso para optimizar el rendimiento es comprender los patrones de consulta reales y esperados. Una vez que conozcas bien los patrones de consulta de tu aplicación, podrás elaborar tu modelo de datos y elegir los índices adecuados.

Los desarrolladores de MongoDB tienen acceso a varias herramientas potentes que les permiten mejorar el rendimiento. Pero eso no significa que se puedan ignorar los perfiles y patrones de consulta.

Por ejemplo, una forma fácil de aumentar el rendimiento es analizar tus patrones de consulta y comprender dónde puedes incrustar los datos. Otras formas de reforzar el rendimiento de MongoDB tras identificar tus principales patrones de consulta son:

  • Asegurarte de que tienes índices en los campos contra los que consultas.
  • Almacenando los resultados de las subconsultas frecuentes en los documentos para reducir la carga de lectura.
  • Echar un vistazo a tus registros para ver si hay consultas lentas, y luego comprobar tus índices.

Revisar la indexación y el modelado de datos

Al hacer tu modelo de datos, decidirás cómo modelar las relaciones entre los datos. Elegir cuándo incrustar un documento en lugar de crear una referencia a través de documentos separados en diferentes colecciones, por ejemplo, es un ejemplo de consideración específica de la aplicación.

Una gran ventaja de los documentos JSON es que permiten a los desarrolladores modelar los datos en función de los requisitos de la aplicación. La anidación de subdocumentos y matrices te ayuda a modelar relaciones complejas entre los datos aprovechando los documentos de texto simple.

También puedes utilizar MongoDB para modelar lo siguiente:

  • Datos geoespaciales
  • Estructuras tabulares, planas y en columnas
  • Pares clave-valor simples
  • Datos de series temporales
  • Aristas y nodos de estructuras de datos de gráficos conectados y similares

Supervisar la fragmentación y la replicación

La replicación puede ser fundamental para mejorar el rendimiento, ya que aumenta la disponibilidad de los datos mediante el escalado horizontal. La replicación puede conducir a un mejor rendimiento y a una mayor seguridad a través de la redundancia.

La supervisión del rendimiento puede ser una molestia que requiere recursos y tiempo adicionales para garantizar un buen funcionamiento. Puedes aprovechar las herramientas de supervisión del rendimiento disponibles en el mercado que se adaptan a tus necesidades específicas.

Por ejemplo, Kinsta APM puede obtener información con marca de tiempo sobre las consultas a la base de datos MySQL de tu sitio de WordPress, los procesos PHP, las llamadas HTTP externas y mucho más. También puedes utilizar esta herramienta gratuita para depurar:

  • Llamadas largas a la API
  • Peticiones de URL externas largas
  • Consultas lentas a bases de datos, por nombrar algunas.

En MongoDB, la replicación puede lograrse mediante conjuntos de réplicas que permiten a los desarrolladores copiar los datos de un nodo o servidor primario en varios secundarios. Esto permite que tu replicación ejecute algunas consultas en los secundarios en lugar de en el primario, evitando la contención y conduciendo a un mejor equilibrio de la carga.

Los clusters fragmentados en MongoDB son otra forma de mejorar potencialmente el rendimiento. Al igual que la replicación, la fragmentación puede utilizarse para distribuir grandes conjuntos de datos entre varios servidores.

Aprovechando una clave de fragmentación, los desarrolladores pueden copiar fragmentos o piezas de datos en varios servidores. Estos servidores pueden trabajar juntos para utilizar todos los datos.

La fragmentación tiene sus ventajas, como el escalado horizontal de escrituras/lecturas, una mayor disponibilidad y una mayor capacidad de almacenamiento.

Determinar el uso de la memoria

MongoDB funciona mejor cuando el conjunto de trabajo de una aplicación (es decir, los datos e índices a los que se accede con frecuencia) cabe en la memoria sin problemas. Aunque otros factores son fundamentales para el rendimiento, el tamaño de la RAM es el más importante para el dimensionamiento de la instancia.

Cuando el conjunto de trabajo de una aplicación cabe en la RAM, la actividad de lectura desde el disco debe ser baja. Pero si tu conjunto de trabajo supera la RAM del servidor de instancias o su tamaño, la actividad de lectura empezará a dispararse.

Si ves que esto ocurre, podrías resolver el problema pasando a una instancia más grande que tenga más memoria.

Coloca los campos de valores múltiples al final

Si estás indexando un par de campos, y uno de los campos que quieres consultar utiliza uno de esos operadores «multivalor», debes colocarlos al final del índice. Tienes que ordenar el índice de forma que los campos consultados por valores exactos vayan primero y los operadores «multivalor» aparezcan al final del índice.

Una excepción a esto sería la ordenación por campos. Colócalos entre los campos «multivalor» y los exactos para reducir la cantidad de ordenación en memoria necesaria.

Resumen

Para MongoDB, la velocidad es el nombre del juego. Para devolver las consultas rápidamente, MongoDB aprovecha los operadores para ejecutar tareas matemáticas o lógicas. En pocas palabras, entender los operadores de MongoDB es la clave para dominar MongoDB.

Este artículo destaca algunos de los operadores clave de MongoDB que puedes utilizar en tus datos, como los operadores de comparación, los operadores lógicos, los meta operadores y los operadores de proyección, por nombrar algunos. También te ayuda a entender cómo puedes utilizar los operadores de MongoDB y las mejores prácticas que te permitirán sacarles el máximo partido.

Entre todos los operadores, ¿cuál o cuáles utilizas más a menudo y por qué? Compártelos en los comentarios a continuación: ¡nos encantará conocer tu opinión!

Salman Ravoof

Salman Ravoof is a self-taught web developer, writer, creator, and a huge admirer of Free and Open Source Software (FOSS). Besides tech, he's excited by science, philosophy, photography, arts, cats, and food. Learn more about him on his website, and connect with Salman on Twitter.