2011-12-08 21 views
24

¿Cómo se usa el punto en el nombre del campo?¿Cómo se usa el punto en el nombre del campo?

veo error en el ejemplo:

db.test2.insert({ "a.a" : "b" }) 

can't have . in field names [a.a] 
+0

'¿Qué hay de "un \ .a"'? –

+0

'" a \ .a "' no parece hacer ninguna diferencia. La cadena todavía se evalúa como '" a.a "' – codr

Respuesta

3

podía comprender que pueden utilizar puntos en las consultas. Ver: http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

Debido a este símbolo de punto especial, significa que no puede usarlo en los nombres de campo. Al igual que no puede usar el símbolo de punto en los identificadores en la mayoría de los lenguajes de programación.

Puede escribir la consulta db.test2.find({ "a.a" : "b" }), pero si desea poder escribir una consulta de este tipo, debe insertar su objeto así: db.test2.insert({"a": {"a": "b"}}). Esto creará un documento con el campo llamado "a" con el valor del documento embebido que contiene el campo denominado "a" (nuevamente) con el valor "b".

44

Puede reemplazar los símbolos de puntos de su nombre de campo a Unicode equivalente de \uff0E

db.test.insert({"field\uff0ename": "test"}) 
db.test.find({"field\uff0ename": "test"}).forEach(printjson) 
{ "_id" : ObjectId("5193c053e1cc0fd8a5ea413d"), "field.name" : "test" } 

Ver más:

  1. http://docs.mongodb.org/manual/faq/developers/#faq-dollar-sign-escaping
  2. http://docs.mongodb.org/manual/core/document/#dot-notation
+2

. Pensé que unicode para el período era "\ u002e". – William

+3

@William si utiliza el carácter unicode puro que sugiere, de todos modos se convierte en un período ASCII; sería una forma elegante de especificarlo. \ uFFOE es un carácter "FULLWIDTH FULL STOP", y como un carácter no ASCII será ignorado. Un personaje de "ONE DOT LEADER" podría verse mejor, ya que está centrado en su espacio tal como es el período normal. [Acabo de verificar que en los productos de Apple, el personaje 2024 se ve mucho mejor, al igual que un período real.] –

+0

Gran punto usando '\ u002e' codificó correctamente la clave del objeto. sin embargo, la recuperación es engorrosa: doc [unescape ('field \ u002ename')] no funciona para mí. tienes que hacer unescape en una variable separada y luego recuperarlo en consecuencia. Prefiero stringify y guardar el problema es luchar contra Mongo Db Driver –

3

También puede escribir una SONManipulator u canta la biblioteca pymongo que transforma los datos que van y vuelven de mongodb. Hay desventajas; hay un impacto en el rendimiento (el impacto depende de tu caso de uso) y tienes que transformar tus claves cuando haces búsquedas usando find.

Aquí es código con un ejemplo de cómo utilizarlo en el comentario de la clase KeyTransform:

from pymongo.son_manipulator import SONManipulator 

class KeyTransform(SONManipulator): 
    """Transforms keys going to database and restores them coming out. 

    This allows keys with dots in them to be used (but does break searching on 
    them unless the find command also uses the transform). 

    Example & test: 
     # To allow `.` (dots) in keys 
     import pymongo 
     client = pymongo.MongoClient("mongodb://localhost") 
     db = client['delete_me'] 
     db.add_son_manipulator(KeyTransform(".", "_dot_")) 
     db['mycol'].remove() 
     db['mycol'].update({'_id': 1}, {'127.0.0.1': 'localhost'}, upsert=True, 
          manipulate=True) 
     print db['mycol'].find().next() 
     print db['mycol'].find({'127_dot_0_dot_0_dot_1': 'localhost'}).next() 

    Note: transformation could be easily extended to be more complex. 
    """ 

    def __init__(self, replace, replacement): 
     self.replace = replace 
     self.replacement = replacement 

    def transform_key(self, key): 
     """Transform key for saving to database.""" 
     return key.replace(self.replace, self.replacement) 

    def revert_key(self, key): 
     """Restore transformed key returning from database.""" 
     return key.replace(self.replacement, self.replace) 

    def transform_incoming(self, son, collection): 
     """Recursively replace all keys that need transforming.""" 
     for (key, value) in son.items(): 
      if self.replace in key: 
       if isinstance(value, dict): 
        son[self.transform_key(key)] = self.transform_incoming(
         son.pop(key), collection) 
       else: 
        son[self.transform_key(key)] = son.pop(key) 
      elif isinstance(value, dict): # recurse into sub-docs 
       son[key] = self.transform_incoming(value, collection) 
     return son 

    def transform_outgoing(self, son, collection): 
     """Recursively restore all transformed keys.""" 
     for (key, value) in son.items(): 
      if self.replacement in key: 
       if isinstance(value, dict): 
        son[self.revert_key(key)] = self.transform_outgoing(
         son.pop(key), collection) 
       else: 
        son[self.revert_key(key)] = son.pop(key) 
      elif isinstance(value, dict): # recurse into sub-docs 
       son[key] = self.transform_outgoing(value, collection) 
     return son 
0
def remove_dots(data): 
    for key in data.keys(): 
     if type(data[key]) is dict: data[key] = remove_dots(data[key]) 
     if '.' in key: 
      data[key.replace('.', '\uff0E')] = data[key] 
      del data[key] 
    return data 

este método recursivo reemplaza todos los caracteres de punto de claves de un diccionario con \ uff0E según lo sugerido por Fisk

+0

Debe usar: if isinstance (date [key] , dict) –

+0

for loop ya usa la lista de teclas disponibles, no creo que sea necesario poner otro si control – tuku

0

Inicialmente utilicé una recursión simple para reemplazar todo "." caracteres con su equivalente unicode, pero se dio cuenta de que incluso los puntos en los valores estaban siendo reemplazados. Así que pensé que deberíamos reemplazar los puntos solo de las claves e hicimos los cambios como corresponda en caso de que "if isinstance (input, dict)". Pensé que debería ser una condición suficiente para hacer la magia pero olvidé que el valor dict también puede ser un dict o una lista y luego finalmente agregué ese control que si el valor de un dict no era una cadena, entra recursivamente y finalmente capaz de encontrar esta solución que eventualmente hizo el truco.

def remove_dots(data): 
    if isinstance(data, dict): 
      return {remove_dots(key): value if isinstance(value, str) else remove_dots(value) for key,value in data.iteritems()} 
    elif isinstance(data, list): 
      return [remove_dots(element) for element in data] 
    elif isinstance(data, str): 
      return data.replace('.','\u002e') 
    else:                        
      return data 
+0

Reemplazar 'entrada' con 'datos' porque su variable se llama datos. Además, el uso de 'entrada' sombrea la función incorporada de entrada() que es de forma pobre. Solo debe cambiar los valores ya que los períodos son necesarios para la selección de objetos dentro de las teclas. –

0

que sustituyen el valor de clave usando myString.replace (". "" \ U2024") antes de insertarlo en la JSONObject.

0

Realmente me he encontrado con este problema al tratar de serializar Diccionarios y tal, donde el punto ofensivo puede aparecer como un nombre de clave. Editado para mostrar las referencias.

La rápida y sucia C# enfoque:

using MongoDB.Bson; 
using Newtonsoft.Json.Linq; 
using System.Text.RegularExpressions; 

public static T Sanitize<T>(T obj) 
{ 
     var str = JObject.FromObject(obj).ToJson(); 
     var parsed = Regex.Replace(str, @"\.(?=[^""]*"":)", "_"); //i.e. replace dot with underscore when found as a json property name { "property.name": "don't.care.what.the.value.is" } 
     return JObject.Parse(parsed).ToObject<T>(); 
} 
Cuestiones relacionadas