Overview
MongoDB 5.0 añade un soporte mejorado para los nombres de campo que tienen el prefijo de dólar ($) o que contienen puntos (.). Las reglas de validación para almacenar datos se han actualizado para facilitar el trabajo con fuentes de datos que utilizan estos caracteres. Sin embargo, se desaconseja el uso de estos caracteres dentro de los nombres de los campos, porque MongoDB no admite algunas funcionalidades con estos campos.
En la mayoría de los casos, los datos almacenados con nombres de campo como estos no son directamente accesibles. Es necesario usar métodos auxiliares como
$getField$setField, y en consultas que acceden a esos $literal campos.
Las reglas de validación del nombre del campo no son las mismas para todos los tipos de operaciones de almacenamiento. Esta página resume cómo las diferentes operaciones de inserción y actualización manejan los nombres de campo con el prefijo dólar ($).
Operaciones de inserción
Los campos con prefijo de dólar ($) están permitidos tanto como nombres de campos de nivel superior como de campos anidados para inserciones.
db.sales.insertOne( { "$price": 50.00, "quantity": 30 } )
Se permite el uso de campos prefijados con el símbolo de dólar ($) en inserciones que utilizan palabras reservadas. Nombres de operadores como $inc se pueden usar como nombres de campos, así como palabras como id, db y ref.
db.books.insertOne( { "$id": "h1961-01", "location": { "$db": "novels", "$ref": "2007042768", "$inc": true } } )
Una actualización que crea un nuevo documento durante una inserción y actualización se trata como un insert en lugar de un update para la validación del nombre de campo. Las$inserciones y actualizaciones pueden aceptar campos con el prefijo dólar (). Sin embargo, las inserciones y actualizaciones son un caso especial, y operaciones de actualización similares pueden causar un error si la match parte de la actualización selecciona un documento existente.
Este código de muestra tiene upsert: true, por lo que insertará un nuevo documento si la colección aún no contiene un documento que coincida con el término de query, { "date": "2021-07-07" }. Si este código de muestra coincide con un documento existente, la operación de actualizar fallará dado que $hotel tiene un prefijo de signo de dólar ($).
db.expenses.updateOne( { "date": "2021-07-07" }, { $set: { "phone": 25.17, "$hotel": 320.10 } }, { upsert: true } )
Actualizaciones de reemplazo de documentos
Los operadores de actualización reemplazan los campos existentes con nuevos documentos o modifican esos campos. En los casos en que la actualización realiza un reemplazo, los nombres de campo de nivel superior con prefijo de dólar ($) no están permitidos.
Considere un documento como
{ "_id": "E123", "address": { "$number": 123, "$street": "Elm Road" }, "$rooms": { "br": 2, "bath": 1 } }
Podrías usar un operador de actualización que reemplace un documento existente para modificar el campo address.$street, pero no podrías actualizar el campo $rooms de esa manera.
db.housing.updateOne( { "_id": "E123" }, { $set: { "address.$street": "Elm Ave" } } )
Utiliza $setField como parte de una pipeline de agregación para actualizar de nivel superior campos con prefijo de dólar ($) como $rooms.
Actualizaciones que modifican documentos
Cuando una actualización modifica, en lugar de sustituir, los campos existentes del documento, los campos con prefijo de dólar ($) pueden ser nombres de campos de nivel superior. Los subcampos se pueden acceder directamente, pero se necesita un método asistente para acceder a los campos de nivel superior.
Considera una colección con documentos como este registro de inventario:
{ _id: ObjectId("610023ad7d58ecda39b8d161"), "part": "AB305", "$bin": 200, "quantity": 100, "pricing": { sale: true, "$discount": 60 } }
El subcampo pricing.$discount puede consultarse directamente.
db.inventory.findAndModify( { query: { "part": { $eq: "AB305" } }, update: { $inc: { "pricing.$discount": 10 } } } )
Utilice $getField y para acceder al valor $literal del $bin campo de nivel superior.
db.inventory.findAndModify( { query: { $expr: { $eq: [ { $getField: { $literal: "$bin" } }, 200 ] } }, update: { $inc: { "quantity": 10 } } } )
Actualizaciones usando pipelines de agregación
Utiliza $setField, $getField y $literal en la etapa $replaceWith para modificar campos con prefijo de dólar ($) en una pipelinede agregación.
Considere una colección de registros escolares como:
{ "_id": 100001, "$term": "fall", "registered": true, "grade": 4 }
Cree una nueva colección para el semestre de primavera utilizando una pipeline para actualizar el campo $term con el prefijo dólar ($).
db.school.aggregate( [ { $match: { "registered": true } }, { $replaceWith: { $setField: { field: { $literal: "$term" }, input: "$$ROOT", value: "spring" } } }, { $out: "spring2022" } ] )
Evite nombres de campos ambiguos
No utilice un nombre de campo que sea igual a la notación de puntos para un campo incrustado. Si tiene un documento con un campo incrustado { "a" : { "b": ... } }, los demás documentos de esa colección no deben tener un campo de nivel superior "a.b".
Si puede referenciar un campo incrustado y un campo de nivel superior de la misma manera, las operaciones de indexación y fragmentación ocurren en el campo incrustado. No se puede indexar ni fragmentar en el campo de nivel superior "a.b" mientras la colección tiene un campo incrustado al que se hace referencia de la misma manera.
Por ejemplo, si su colección contiene documentos con un campo incrustado { "a" : { "b": ... } } y un campo de nivel superior "a.b", las operaciones de indexación y fragmentación ocurren en el campo incrustado. No es posible indexar o fragmentar en el campo de nivel superior "a.b" cuando su colección también contiene un campo incrustado { "a" : { "b": ... } }.
Restricciones generales
Además de las reglas de validación de almacenamiento mencionadas arriba, existen algunas restricciones generales sobre el uso de nombres de campos con prefijo de dólar ($). Estos campos no pueden:
Estar indexado
Ser utilizado como parte de una clave de partición
Ser validado usando
$jsonSchemaSe puede modificar con una secuencia de escape
Se utiliza con cifrado a nivel de campo
Utilizarse como subcampo en un documento
_id
Advertencia
Posible pérdida de datos con signos de dólar ($) y puntos (.)
Existe una pequeña posibilidad de pérdida de datos cuando se utilizan nombres de campo con el prefijo dólar ($) o nombres de campo que contienen puntos (.) si estos nombres de campo se utilizan junto con escrituras no reconocidas (nivel de confirmación de escritura w=0) en servidores que sean anteriores a MongoDB 5.0.
Al ejecutar los comandos insertar, actualizar y findAndModify, los drivers que son compatibles con la versión 5.0 remueven las restricciones sobre el uso de documentos con nombres de campo que tienen el prefijo de dólar ($) o que contienen puntos (.). Estos nombres de campos generaron un error del lado del cliente en versiones anteriores del controlador.
Las restricciones se eliminan independientemente de la versión del servidor a la que esté conectado el controlador. Si un controlador 5.0 envía un documento a un servidor más antiguo, el documento será rechazado sin enviar un error.
Advertencia
Preocupaciones sobre la importación y exportación con signos de dólar ($) y puntos (.)
A partir de MongoDB 5.0, los nombres de los campos del documento pueden tener prefijo de dólar ($) y pueden contener puntos (.). Sin embargo, mongoimport y mongoexport pueden no funcionar como se espera en algunas situaciones con nombres de campos que utilizan estos caracteres.
MongoDB Extended JSON v2 no puede diferenciar entre los contenedores de tipo y los campos que tienen el mismo nombre que los contenedores de tipo. No utilices formatos JSON extendidos en contextos donde las representaciones BSON correspondientes puedan incluir claves con prefijo de dólar ($). El mecanismo DBRef es una excepción a esta regla general.
También hay restricciones en el uso de mongoimport y mongoexport con puntos (.) en los nombres de campo. Dado que los archivos CSV utilizan el punto (.) para representar jerarquías de datos, un punto (.) en el nombre de un campo se interpretará incorrectamente como un nivel de anidamiento.