Как использовать точку в имени поля? - PullRequest
25 голосов
/ 08 декабря 2011

Как использовать точку в имени поля?

Я вижу ошибку в примере:

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

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

Ответы [ 7 ]

46 голосов
/ 15 мая 2013

Вы можете заменить точечные символы вашего имени поля на Unicode, эквивалентный \uff0E

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

Подробнее:

  1. http://docs.mongodb.org/manual/faq/developers/#faq-dollar-sign-escaping
  2. http://docs.mongodb.org/manual/core/document/#dot-notation
4 голосов
/ 09 декабря 2011

На самом деле вы можете использовать точки в запросах. Смотри: http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

Из-за этого специального символа точки вы не можете использовать его в именах полей. Как будто вы не можете использовать символ точки в идентификаторах в большинстве языков программирования.

Вы можете написать запрос db.test2.find({ "a.a" : "b" }), но если вы хотите иметь возможность написать такой запрос, вам нужно вставить свой объект следующим образом: db.test2.insert({"a": {"a": "b"}}). Это создаст документ с полем с именем "a" со значением внедренного документа, содержащим поле с именем "a" (снова) со значением "b".

3 голосов
/ 20 декабря 2013

Вы также можете написать SONManipulator , используя библиотеку pymongo, которая преобразует данные, поступающие в mongodb и обратно.Есть минусы;наблюдается снижение производительности (влияние зависит от вашего варианта использования), и вы должны преобразовывать ключи, когда выполняете поиск с использованием find.

Вот код с примером его использования в комментарии для класса 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
1 голос
/ 29 апреля 2016

Я заменил значение ключа, используя myString.replace (".", "\ U2024"), прежде чем вставить его в JsonObject.

0 голосов
/ 12 февраля 2017

Я действительно сталкивался с этой проблемой только при попытке сериализовать словари и такие, где оскорбительная точка может появляться в качестве имени ключа.Отредактировано, чтобы показать ссылки.

Быстрый и грязный подход C #:

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>();
}
0 голосов
/ 17 февраля 2016

Изначально я использовал простую рекурсию, чтобы заменить все "."символы с его юникодным эквивалентом, но понял, что даже точки в значениях заменяются.Поэтому я подумал, что мы должны заменить точки только из ключей, и внес соответствующие изменения в случае «если isinstance (input, dict)».Я думал, что это должно быть достаточным условием для магии, но я забыл, что значение dict также может быть dict или списком, и затем я наконец добавил эту проверку, что если значение dict не было строкой, то идем внутрь рекурсивно и наконецв состоянии придумать это решение, которое в конечном итоге добилось цели.

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 голосов
/ 02 февраля 2015
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

этот рекурсивный метод заменяет все точечные символы из ключей dict на \ uff0E как предложено Фиск

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...