Parece mongo no permitir la inserción de llaves con un punto (.) o un símbolo de dólar ( $ ), sin embargo cuando he importado un archivo JSON que contiene un punto en que el uso de la mongoimport herramienta funcionó bien. El conductor se quejan, tratando de insertar el elemento en cuestión.

Esto es lo que el documento se ve como en la base de datos:

{
    "_id": {
        "$oid": "..."
    },
    "make": "saab",
    "models": {
        "9.7x": [
            2007,
            2008,
            2009,
            2010
        ]
    }
}

Estoy haciendo esta mal y no se debe usar el hash de mapas con datos externos (es decir, los modelos o puedo escapar el punto de alguna manera? Tal vez me estoy pensando muy mucho de Javascript-como.

19 Comentarios

  1. 61

    MongoDB no admite teclas con un punto en ellos, por lo que vamos a tener para preprocesar su archivo JSON para quitar y reemplazar con ellos antes de su importación o estarás preparando para todo tipo de problemas.

    No hay un estándar de la solución a este problema, el mejor enfoque es demasiado dependiente de los detalles de la situación. Pero me gustaría evitar cualquier tecla del codificador/decodificador de enfoque si es posible, ya que voy a seguir pagando el inconveniente de que en perpetuidad, donde un JSON reestructurar presumiblemente por ser un costo por única vez.

    • Sí, soy consciente de que, he leído la documentación y la implementación de un driver para Node.js. Me preguntaba ¿cuál es la forma estándar de tratar con esto. Porque me gustaría búsqueda basada en los valores también. Debo construir y codificador y decodificador de función para reemplazar un . con [dot]? O debería reestructurar mi JSON de alguna manera para evitar que todos juntos?
    • Creo que no hay una forma estándar, el mejor enfoque es demasiado dependiente de los detalles de la situación. Pero me gustaría evitar cualquier tecla del codificador/decodificador de enfoque si es posible, ya que voy a seguir pagando el inconveniente de que en perpetuidad, donde un JSON reestructurar presumiblemente por ser un costo por única vez.
    • bien gracias por el consejo, se debe incorporar en la respuesta, y me lo marca como la respuesta a esta pregunta.
    • Bueno, he añadido que en la respuesta.
    • Corrió en esta situación de nuevo. Esto parece ocurrir no tanto con la aplicación de los nombres clave, que podemos controlar y a menudo necesitan de la consulta, pero con datos suministrados por el usuario en anidados estructuras de datos, que no podemos controlar, pero (a) desea almacenar en Mongo, (b) sabemos que los campos específicos de que esto pudiera ocurrir (por ejemplo, models aquí), y (c) que no;t necesidad de consultar mediante el nombre de la clave en Mongo. Así, un patrón que me instalé en es JSON.stringify este campo en guardar, y ‘JSON.parse` en recuperar.
    • Si es necesario, puede proporcionar {check_keys: false} opción para eludir este problema.
    • OMG que usted haya encontrado la MongoDB equivalente de el paso del noroeste. Creo que esto debe ser aceptado respuesta.
    • cuando se agregue el {check_keys: false}?
    • db.collection_foo.update({esto: «que»}, {$conjunto: {a:»b»}}, {check_keys: false})
    • Sólo me encontrado con este problema de esta semana. Pero, no fue mongo que fue lanzar la excepción fue NodeJS. (Sobre el que MongoDb es construido) JSON.analizar que es lo que produce el error. Siento que esto es un desarrollo relativamente reciente, y se preguntan por qué NodeJS (o es ES6) que no le gusta el período. En cualquier caso, yo sólo tomó el uso de la Matriz en lugar de «hash» de las tablas construidas a partir de objetos de JavaScript.
    • Tzury Bar Yochay, puede {check_keys: false} opción de ser utilizado en C# conductor? No pude encontrar nada…

  2. 18

    La Mongo docs sugieren la sustitución de caracteres ilegales tales como $ y . con sus equivalentes de unicode.

    En estas situaciones, las llaves se debe sustituir la reserva de $ y . los caracteres. Cualquier personaje es suficiente, pero considerar el uso de Unicode lleno de ancho equivalentes: U+FF04 (es decir,»$») y U+FF0E (es decir,».»).

    • Eso suena como una receta para la depuración masiva de los dolores de cabeza por el camino.
    • Que incluso las necesidades de imitar?
    • Creo que el docs significar algo así como db.test.insert({"field\uff0ename": "test"})
    • -1 R. Esa es una idea terrible – ¿y si alguien está realmente tratando de usar los caracteres unicode como una clave? A continuación, tienes un silencio de error que va a hacer quién sabe qué en su sistema. No uso ambiguo de los métodos de escape como eso. B. el mongo docs no podemos decir que, probablemente porque alguien se dio cuenta de su terrible idea
    • los médicos dicen que, no sólo en esa página. docs.mongodb.com/v3.0/faq/developers/…. Pero estoy de acuerdo, es una mala idea. 🙂
    • Tengo que quitar la recomendación : ) github.com/mongodb/docs/commit/…
    • sombrero de punta a usted, señor 🙂

  3. 16

    Como se ha mencionado en otras respuestas MongoDB no permite $ o . personajes como asignar teclas debido a restricciones en los nombres de campo. Sin embargo, como se mencionó en Signo De Dólar Operador Escapar esta restricción no impide la inserción de documentos con estas claves, no sólo evita la actualización o consulta.

    El problema de la simple sustitución de . con [dot] o U+FF0E (como se menciona en otra parte de esta página) es, ¿qué sucede cuando el usuario legítimamente quiere guardar la clave de [dot] o U+FF0E?

    Un enfoque que Fantom del afMorphia conductor toma, es el uso de secuencias de escape unicode similar a la de Java, pero garantizando el carácter de escape se escapó de la primera. En esencia, la siguiente cadena de sustituciones se realizan (*):

    \  -->  \
    $  -->  \u0024
    .  -->  \u002e

    Inversa de reemplazo se hace cuando el mapa de teclas posteriormente leer de MongoDB.

    O en Fantom código:

    Str encodeKey(Str key) {
        return key.replace("\", "\\").replace("$", "\u0024").replace(".", "\u002e")
    }
    
    Str decodeKey(Str key) {
        return key.replace("\u002e", ".").replace("\u0024", "$").replace("\\", "\")
    }

    La única vez que un usuario debe ser consciente de este tipo de conversiones es a la hora de construir las consultas para tales claves.

    Dado que es común para almacenar dotted.property.names en bases de datos para la configuración de los efectos creo que este enfoque es preferible a la simple prohibición de todas esas mapa de teclas.

    (*) afMorphia realiza realmente completo /adecuado unicode escapar de las reglas de como se menciona en De escape Unicode sintaxis en Java pero el se describe la sustitución de la secuencia funciona igual de bien.

    • Debe utilizar //g para reemplazar todas las apariciones y no la primera. Además, el uso de la anchura completa equivalentes en Martin Konecny la respuesta parece ser una buena idea. Por último, una barra diagonal inversa es suficiente para la codificación. key.replace(/\./g, '\uff0e').replace(/\$/g, '\uff04').replace(/\\/g, '\uff3c')
    • El código está en un Java como la sintaxis, por lo que reemplace en realidad reemplazar todas las apariciones, y el doble de barras diagonales inversas son necesarios para escapar de las barras diagonales inversas. Y de nuevo, usted necesita para introducir alguna forma de escape para asegurarse de todo de los casos están cubiertos. Alguien, en algún momento, puede que en realidad quieren una clave de U+FF04.
  4. 10

    Puede intentar usar un hash de la clave en lugar del valor y, a continuación, almacenar el valor en el JSON valor.

    var crypto = require("crypto");   
    
    function md5(value) {
        return crypto.createHash('md5').update( String(value) ).digest('hex');
    }
    
    var data = {
        "_id": {
            "$oid": "..."
        },
        "make": "saab",
        "models": {}
    }
    
    var version = "9.7x";
    
    data.models[ md5(version) ] = {
        "version": version,
        "years" : [
            2007,
            2008,
            2009,
            2010
        ]
    }

    A continuación, acceder a los modelos utilizando el hash más tarde.

    var version = "9.7x";
    collection.find( { _id : ...}, function(e, data ) {
        var models = data.models[ md5(version) ];
    }
    • Me gusta esto, limpio con la solución de 1-way hash y muy similar a la forma en que funcionan las cosas bajo el capó.
    • El problema con el uso de los hash de las claves, es que ellos no se no garantiza que sea único, y que con frecuencia producen collisions. Además de calcular un hash criptográfico cada vez que desee acceder a un mapa no parece la solución más óptima a mí.
    • ¿Por qué esto es mejor que la sustitución del período con un carácter especial o secuencia?
  5. 10

    Una solución que se me implementado con el que estoy muy contento con consiste en partir el nombre de clave y valor en dos campos separados. De esta manera, puedo mantener los caracteres exactamente el mismo, y no preocuparse acerca de cualquiera de los análisis de las pesadillas. El doc se vería como:

    {
        ...
        keyName: "domain.com",
        keyValue: "unregistered",
        ...
    }

    También se puede consultar esta bastante fácil, sólo por hacer un find en los campos keyName y keyValue.

    Así que en lugar de:

     db.collection.find({"domain.com":"unregistered"})

    que no funcionan según lo esperado, se debe ejecutar:

    db.collection.find({keyName:"domain.com", keyValue:"unregistered"})

    y se devolverá a la espera del documento.

    • Cómo lo hizo? Podría Usted por favor me ayude con ese mismo caso.
    • He añadido un ejemplo de consulta. ¿Eso ayuda?
  6. 10

    La última versión estable (v3.6.1) de la MongoDB soporta los puntos (.) en las claves o nombres de campo ahora.

    Los nombres de campo pueden contener puntos (.) y el dólar ($) caracteres ahora

    • Incluso si el servidor lo admite ahora, el conductor cheque por $ y puntos claves y no las acepta. Por lo tanto, Mongo sólo teóricamente soporta puntos y el dólar de los personajes. Prácticamente esto no es utilizable todavía 🙁
    • Tal vez usted está utilizando algunos de los antiguos o incompatibles cliente. He estado usando esto en mis servidores de producción sin ningún tipo de sudor. He comprobado para NodeJS y los clientes de Java.
    • Con Java que definitivamente no funciona! Pruebe el siguiente comando: mongoClient.getDatabase("mydb").getCollection("test").insertOne(new Document("value", new Document("key.with.dots", "value").append("$dollar", "value"))); falla usando mongodb-controlador.3.6.3 y MongoDB 3.6.3.
    • De hecho, acabo de probar con una instalación mongodb-4.1.1 y pymongo-3.7.1. Puedo agregar los documentos que contienen las claves con . con robomongo pero no de pymongo, se plantea el alféizar de la InvalidDocument: key '1.1' must not contain '.' queremos que había sido fijada por ahora…
    • He probado con el servidor de mongodb 4.0.9 y controlador java 3.10.2 pero éste no acepta un punto en el nombre de la clave. es extraño que cuando se pruebe que el uso de robomongo funciona…
  7. 4

    De la MongoDB docs «el ‘.’ personaje no debe aparecer en cualquier lugar del nombre de la clave». Parece que vas a tener que venir para arriba con un esquema de codificación no.

  8. 3

    Usted necesita para escapar de las teclas. Ya que parece que la mayoría de la gente no sabe la manera correcta de cadenas de escape, aquí los pasos:

    1. elegir un carácter de escape (mejor que elegir un personaje que rara vez se utiliza). Por ejemplo. ‘~’
    2. Escapar, primero reemplazar todos los casos el carácter de escape con alguna secuencia antepone con su carácter de escape (por ejemplo, ‘ ~ ‘ – > ‘~t’), y luego reemplace cualquier carácter o secuencia que usted necesita para escapar con algunos secuencia antepone con su carácter de escape. Por ejemplo. ‘.’ -> ‘~p’
    3. A unescape, retire primero la secuencia de escape de todas las instancias de su segunda secuencia de escape (por ejemplo, ‘~p’ -> ‘.’), luego transformar su secuencia de caracteres de escape para un solo carácter de escape(por ejemplo, ‘~s’ -> ‘~’)

    También, recuerde que mongo también no permitir claves para empezar con ‘$’, así que usted tiene que hacer algo similar no

    Aquí está el código que lo hace:

    //returns an escaped mongo key
    exports.escape = function(key) {
      return key.replace(/~/g, '~s')
                .replace(/\./g, '~p')
                .replace(/^$/g, '~d')
    }
    
    //returns an unescaped mongo key
    exports.unescape = function(escapedKey) {
      return escapedKey.replace(/^~d/g, '$')
                       .replace(/~p/g, '.')
                       .replace(/~s/g, '~')
    }
    • Esta escapando todavía puede romper, si usted tiene condiciones como ‘.~p.’. Aquí el escaparon de la cadena ser ‘~p~~p~p’. Unescaping le dará ‘.~..’, que es diferente de la cadena real.
    • Estás en lo cierto! He corregido la explicación y el ejemplo de funciones de escape. Déjeme saber si todavía están rotos!
  9. 3

    Una tardía respuesta, pero si uso la Primavera y el Mongo, la Primavera puede gestionar la conversión para usted con MappingMongoConverter. Es la solución por JohnnyHK pero manejado por la Primavera.

    @Autowired
    private MappingMongoConverter converter;
    
    @PostConstruct
    public void configureMongo() {
     converter.setMapKeyDotReplacement("xxx");
    }

    Si su almacenados Json es :

    { "axxxb" : "value" }

    A través de la Primavera (MongoClient) se puede leer como :

    { "a.b" : "value" }
  10. 1

    Yo uso los siguientes escapar en JavaScript para cada objeto clave:

    key.replace(/\/g, '\\').replace(/^$/, '\$').replace(/\./g, '\_')

    Lo que me gusta de ella es que se reemplaza sólo $ en el comienzo, y no utilizar caracteres unicode que puede ser difícil de usar en la consola. _ es para mí mucho más fácil de leer que un carácter unicode. Asimismo, no reemplazar un conjunto de caracteres especiales ($, .) con otro (unicode). Pero se escapa con la tradicional \.

    • Y si alguien utiliza un _ en cualquiera de sus claves, obtendrá errores.
  11. 1

    No es perfecto, pero funciona en la mayoría de las situaciones: reemplazar los caracteres prohibidos por algo más. Puesto que es en las teclas, estos nuevos caracteres debe ser bastante raro.

    /** This will replace \ with ⍀, ^$ with '₴' and dots with ⋅  to make the object compatible for mongoDB insert. 
    Caveats:
        1. If you have any of ⍀, ₴ or ⋅ in your original documents, they will be converted to $.upon decoding. 
        2. Recursive structures are always an issue. A cheap way to prevent a stack overflow is by limiting the number of levels. The default max level is 10.
     */
    encodeMongoObj = function(o, level = 10) {
        var build = {}, key, newKey, value
        //if (typeof level === "undefined") level = 20     //default level if not provided
        for (key in o) {
            value = o[key]
            if (typeof value === "object") value = (level > 0) ? encodeMongoObj(value, level - 1) : null     //If this is an object, recurse if we can
    
            newKey = key.replace(/\/g, '⍀').replace(/^$/, '₴').replace(/\./g, '⋅')    //replace special chars prohibited in mongo keys
            build[newKey] = value
        }
        return build
    }
    
    /** This will decode an object encoded with the above function. We assume the structure is not recursive since it should come from Mongodb */
    decodeMongoObj = function(o) {
        var build = {}, key, newKey, value
        for (key in o) {
            value = o[key]
            if (typeof value === "object") value = decodeMongoObj(value)     //If this is an object, recurse
            newKey = key.replace(/⍀/g, '\').replace(/^₴/, '$').replace(/⋅/g, '.')    //replace special chars prohibited in mongo keys
            build[newKey] = value
        }
        return build
    }

    Aquí es una prueba:

    var nastyObj = {
        "sub.obj" : {"$dollar\backslash": "$\.end$"}
    }
    nastyObj["$you.must.be.kidding"] = nastyObj     //make it recursive
    
    var encoded = encodeMongoObj(nastyObj, 1)
    console.log(encoded)
    console.log( decodeMongoObj( encoded) )

    y los resultados – tenga en cuenta que los valores no se modifican:

    {
      subobj: {
        dollarbackslash: "$\.end$"
      },
      youmustbekidding: {
        subobj: null,
        youmustbekidding: null
      }
    }
    [12:02:47.691] {
      "sub.obj": {
        $dollar\backslash: "$\.end$"
      },
      "$you.must.be.kidding": {
        "sub.obj": {},
        "$you.must.be.kidding": {}
      }
    }
  12. 0

    Para PHP y sustituir el código HTML de valor para el período. Que ".".

    Almacena en MongoDB como este:

      "validations" : {
         "4e25adbb1b0a55400e030000" : {
         "associate" : "true" 
        },
         "4e25adb11b0a55400e010000" : {
           "associate" : "true" 
         } 
       } 

    y el código PHP…

      $entry = array('associate' => $associate);         
      $data = array( '$set' => array( 'validations.' . str_replace(".", `"."`, $validation) => $entry ));     
      $newstatus = $collection->update($key, $data, $options);      
  13. 0

    Lodash pares le permitirá cambiar

    { 'connect.sid': 's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' }

    en

    [ [ 'connect.sid',
    's:hyeIzKRdD9aucCc5NceYw5zhHN5vpFOp.0OUaA6' ] ]

    utilizando

    var newObj = _.pairs(oldObj);
  14. 0

    Puede almacenar como es y convertir a bastante después de

    Escribí este ejemplo en Livescript. Puede utilizar livescript.net sitio web para eval es

    test =
      field:
        field1: 1
        field2: 2
        field3: 5
        nested:
          more: 1
          moresdafasdf: 23423
      field3: 3
    
    
    
    get-plain = (json, parent)->
      | typeof! json is \Object => json |> obj-to-pairs |> map -> get-plain it.1, [parent,it.0].filter(-> it?).join(\.)
      | _ => key: parent, value: json
    
    test |> get-plain |> flatten |> map (-> [it.key, it.value]) |> pairs-to-obj

    Se va a producir

    JS:

    {"field.field1":1,
     "field.field2":2,
     "field.field3":5,
     "field.nested.more":1,
     "field.nested.moresdafasdf":23423,
     "field3":3}

  15. 0

    Doy mi consejo: puede usar JSON.stringify guardar el Objeto/Matriz contiene el nombre de la clave tiene puntos, luego de analizar la cadena al Objeto JSON.analizar a proceso a la hora de obtener datos de la base de datos de

    Otra solución:
    Reestructurar su esquema como:

    key : {
    "keyName": "a.b"
    "value": [Array]
    }
  16. 0

    Última MongoDB soporta teclas con un punto, pero java MongoDB-controlador no está apoyando. Así que para hacer que funcione en Java, me sacó código de repo de github de java-mongo-controlador e hizo los cambios correspondientes en sus isValid Tecla de función, creado nuevo tarro de ella, usando ahora.

  17. 0

    Reemplazar el punto(.) o en dólares($) con otros personajes, que nunca se usan en el documento. Y restaurar el punto(.) o en dólares($) al recuperar el documento. La estrategia de no influir en los datos que el usuario lea.

    Usted puede seleccionar el carácter de todos los personajes.

  18. 0

    El extraño esto es, el uso de mongojs, puedo crear un documento con un punto si puedo configurar el _id mí mismo, sin embargo no puedo crear un documento cuando el _id se genera:

    Funciona:

    db.testcollection.save({"_id": "testdocument", "dot.ted.": "value"}, (err, res) => {
        console.log(err, res);
    });

    No funciona:

    db.testcollection.save({"dot.ted": "value"}, (err, res) => {
        console.log(err, res);
    });

    Pensé por primera vez dat actualización de un documento con un punto clave también trabajaba, pero su identificación el punto como una subclave!

    Ver cómo mongojs controla el punto (subclave), voy a asegurarme de que mis llaves no contienen un punto.

  19. -1

    /home/user/anaconda3/lib/python3.6/site-packages/pymongo/collection.py

    Encontrado en los mensajes de error. Si utiliza anaconda (encontrar el corresponsal de archivo si no), simplemente cambiar el valor de check_keys = True a False en el archivo indicado anteriormente. Que va a funcionar!

Dejar respuesta

Please enter your comment!
Please enter your name here