105 votes

MongoDB point (.) dans le nom de la clé

Il semble que Mongo ne permette pas l'insertion de clés avec un point (.) ou un signe dollar ($). Cependant, lorsque j'ai importé un fichier JSON contenant un point à l'aide de l'outil mongoimport, tout s'est bien passé. Le pilote se plaint d'essayer d'insérer cet élément.

Voici à quoi ressemble le document dans la base de données :

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

Est-ce que je m'y prends mal et ne devrais pas utiliser des cartes de hachage de cette manière avec des données externes (c'est-à-dire les modèles) ou puis-je échapper au point d'une manière ou d'une autre ? Je pense peut-être trop à la manière de Javascript.

10voto

Henry Wang Points 301

Vous pouvez essayer d'utiliser un hachage dans la clé au lieu de la valeur, puis de stocker 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 pourrez alors accéder aux modèles en utilisant le hachage plus tard.

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

8voto

Abhidemon Points 490

Il est désormais pris en charge

MongoDb 3.6 supporte à la fois points y dollar dans les noms de champs. Voir ci-dessous JIRA : https://jira.mongodb.org/browse/JAVA-2810

La mise à niveau de votre Mongodb vers 3.6+ semble être la meilleure solution.

4voto

B T Points 4868

Tu dois t'échapper des clés. Comme il semble que la plupart des gens ne savent pas comment échapper correctement les chaînes de caractères, voici les étapes à suivre :

  1. choisissez un caractère d'échappement (le mieux est de choisir un caractère rarement utilisé). Par exemple, '~'.
  2. Pour s'échapper, remplacez d'abord toutes les occurrences du caractère d'échappement par une séquence précédée de votre caractère d'échappement (par exemple, '~' -> '~t'), puis remplacez le caractère ou la séquence que vous devez échapper par une séquence précédée de votre caractère d'échappement. Par exemple, "." -> "~p".
  3. Pour déséchapper, supprimez d'abord la séquence d'échappement de toutes les instances de votre deuxième séquence d'échappement (par exemple '~p' -> '.'), puis transformez votre séquence de caractères d'échappement en un seul caractère d'échappement (par exemple '~s' -> '~').

N'oubliez pas non plus que Mongo ne permet pas aux clés de commencer par '$', vous devez donc faire quelque chose de similaire.

Voici un code qui le fait :

// 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, '~')
}

3voto

PomPom Points 1423

Une réponse tardive, mais si vous utilisez Spring et Mongo, Spring peut gérer la conversion pour vous avec MappingMongoConverter . C'est la solution de JohnnyHK mais gérée par Spring.

@Autowired
private MappingMongoConverter converter;

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

Si votre Json stocké est :

{ "axxxb" : "value" }

A travers Spring (MongoClient), il sera lu comme :

{ "a.b" : "value" }

3voto

Teddy Haley Points 23

Comme un autre utilisateur l'a mentionné, l'encodage/décodage peut devenir problématique à l'avenir, il est donc probablement plus simple de remplacer toutes les clés qui ont un point. Voici une fonction récursive que j'ai créée pour remplacer les clés avec des occurrences '.' :

def mongo_jsonify(dictionary):
    new_dict = {}
    if type(dictionary) is dict:
        for k, v in dictionary.items():
            new_k = k.replace('.', '-')
            if type(v) is dict:
                new_dict[new_k] = mongo_jsonify(v)
            elif type(v) is list:
                new_dict[new_k] = [mongo_jsonify(i) for i in v]
            else:
                new_dict[new_k] = dictionary[k]
        return new_dict
    else:
        return dictionary

if __name__ == '__main__':
    with open('path_to_json', "r") as input_file:
        d = json.load(input_file)
    d = mongo_jsonify(d)
    pprint(d)

Vous pouvez modifier ce code pour remplacer également le '$', car c'est un autre caractère que Mongo n'autorise pas dans une clé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X