MongoDB dot (.) Dans le nom de la clé

Il semble que mongo n'autorise pas l'insertion de clés avec un point (.) Ou un signe dollar ($) cependant, lorsque j'ai importé un fichier JSON qui contenait un point à l'aide de l'outil mongoimport, il fonctionnait bien. Le conducteur se plaint d'essayer d'insérer cet élément.

Voici le document dans la base de données:

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

Est-ce que je fais tout cela mal et ne devrait pas utiliser de cartes de hash comme celles-ci avec des données externes (c'est-à-dire les modèles) ou puis-je échapper au point de quelque façon? Peut-être que je pense trop à Javascript.

MongoDB ne prend pas en charge les clés avec un point dans celles-ci, donc vous devrez préprocesser votre fichier JSON pour les supprimer ou les remplacer avant de l'importer ou vous configurerez pour toutes sortes de problèmes.

Il n'y a pas de solution de rechange standard à ce problème, la meilleure approche dépend trop des particularités de la situation. Mais j'éviterais éventuellement toute approche clé d'encodeur / décodeur si possible, car vous continuerez de faire l'inconvénient de cela à perpétuité, où une restructuration JSON serait vraisemblablement un coût ponctuel.

Les Mongo docs suggèrent de remplacer des personnages illégaux tels que $ and . Avec leurs équivalents unicode.

Dans ces situations, les clés devront remplacer les $ et les $ réservés. personnages. Tout caractère est suffisant, mais envisagez d'utiliser les équivalents pleine largeur Unicode: U + FF04 (c.-à-d. "$") Et U + FF0E (c.-à-d. ".").

Comme mentionné dans d'autres réponses MongoDB n'autorise pas $ ou . Les caractères en tant que clés de carte en raison de restrictions sur les noms de champs . Toutefois, tel qu'indiqué dans l' opérateur Dollar Sign Échapper à cette restriction ne vous empêche pas d' insérer des documents avec de telles clés, en les mettant à jour ou en les interrogeant.

Le problème de simplement remplacer . Avec [dot] (comme mentionné dans les commentaires) est ce qui se passe lorsque l'utilisateur veut légitimement stocker la clé [dot] ?

Une approche que le pilote AfMorphia de Fantom prend consiste à utiliser des séquences d'échappement unicode similaires à celle de Java, mais en veillant à ce que tous les caractères d'échappement échappent en premier. Essentiellement, les remplacements de chaînes suivants sont effectués (*):

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

Un remplacement inverse est effectué lorsque les clés de la carte sont ensuite lues depuis MongoDB.

Ou dans le code Fantom :

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

La seule fois qu'un utilisateur doit connaître ces conversions est lors de la construction de requêtes pour ces clés.

Étant donné qu'il est courant de stocker les dotted.property.names dans les bases de données pour des raisons de configuration, je crois que cette approche est préférable de simplement interdire toutes ces clés de carte.

(*) AfMorphia effectue réellement des règles d'échappement unicode pleines / appropriées comme mentionné dans la syntaxe d'échappement Unicode en Java, mais la séquence de remplacement décrite fonctionne aussi bien.

Vous pouvez essayer d'utiliser un hash dans la clé au lieu de la valeur, puis enregistrer cette valeur dans la valeur JSON.

 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 ] } 

Vous accédez ensuite aux modèles à l'aide du hash plus tard.

 var version = "9.7x"; collection.find( { _id : ...}, function(e, data ) { var models = data.models[ md5(version) ]; } 

Une solution que je viens d'implémenter avec laquelle je suis vraiment contente consiste à diviser le nom et la valeur de la clé en deux champs distincts. De cette façon, je peux garder les personnages exactement les mêmes, et je ne m'inquiète pas de l'analyse de ces cauchemars. Le document ressemblerait à:

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

Vous pouvez toujours le consulter facilement, en effectuant une find sur les champs keyName et keyValue .

Lodash pairs vous permettra de changer

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

dans

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

en utilisant

 var newObj = _.pairs(oldObj); 

J'utilise les fonctions suivantes en JavaScript pour chaque touche d'objet:

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

Ce que j'aime à ce sujet, c'est qu'il ne remplace que $ au début, et qu'il n'utilise pas de caractères unicode qui peuvent être difficiles à utiliser dans la console. _ Est pour moi beaucoup plus lisible qu'un personnage unicode. Il ne remplace pas non plus un jeu de caractères spéciaux ( $ ,.) Par un autre (unicode). Mais échappe correctement à la traditionnelle \ .

Vous pouvez le stocker tel quel et le convertir en assez après

J'ai écrit cet exemple sur Livescript. Vous pouvez utiliser le site livescript.net pour l'évaluer

 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 

Il produira

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