27

I'm trying to save a dictionary containing a special character '.' in key portion to the MongoDB. The error is presented below, which clearly states that the key must not contain a special character '.'.

>>> import pymongo
>>> client = pymongo.MongoClient('localhost')
>>> db = client['malware']                                                                                                                                                          
>>> test = db['test']
>>> d = {'.aaa' : '.bbb'}                                                                                                                                                           
>>> test.insert(d)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/site-packages/pymongo/collection.py", line 362, in insert
    self.database.connection)
bson.errors.InvalidDocument: key '.aaa' must not contain '.'

But my current information contains '.' in the key portion of the data, which I need to store to MongoDB. Currently I was just deleting the '.' from the string, another options would be to replace it with '_' or some other special character.

Nevertheless, all results in loss of information, because if I have a key '.aaa' and a key 'aaa' and if I convert '.' into '' then the keys are exactly the same and I lose some information. Why isn't Mongo allowing me to save the '.aaa' into the DB?

Any ideas how to approach the problem?

eleanor
  • 1,514
  • 3
  • 19
  • 40

2 Answers2

30

You can set check_keys to False according to the source:

 test.insert(d,check_keys=False)


 def insert(self, doc_or_docs, manipulate=True,
           safe=None, check_keys=True, continue_on_error=False, **kwargs):

It does indeed work:

In [28]: d = {'.aaa' : '.bbb'}

In [29]: test.insert(d,check_keys=False)
Out[29]: ObjectId('54ea604bf9664e211e8ed4e6')

The docstring states:

  • check_keys (optional): If True check if keys start with '$' or contain '.', raising :class:~pymongo.errors.InvalidName in either case.

You seem to be able to use any character apart from just the two $ or . so a leading underscore or any other character would be fine and probably a better option.

There is info in the faq about escaping :

In some cases, you may wish to build a BSON object with a user-provided key. In these situations, keys will need to substitute the reserved $ and . characters. Any character is sufficient, but consider using the Unicode full width equivalents: U+FF04 (i.e. “$”) and U+FF0E (i.e. “.”).

And the dot-notation faq explains why using . is not a good idea:

MongoDB uses the dot notation to access the elements of an array and to access the fields of an embedded document. To access an element of an array by the zero-based index position, concatenate the array name with the dot (.) and zero-based index position, and enclose in quotes:

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • Thank you for letting me know of this option. Can you briefly describe why Mongo won't allow you to save key with '.' by default and you have to override it in order to do it? This would make a complete answer with an actual explanation why this happens and after that I can accept this answer as correct. Thanks again. – eleanor Feb 22 '15 at 23:04
  • 12
    `insert()` is deprecated, replaced with `insert_one()` which does not have the `check_keys` argument. It has a `bypass_document_validation` argument but this does not have the same effect, it still won't insert a document that has a dot in a key. – Dan Tenenbaum May 30 '17 at 18:14
  • 5
    `check_keys` no longer available. – coding_idiot Jul 06 '18 at 23:45
  • 1
    @coding_idiot : Then what will be the options? – Harsha Biyani Apr 01 '19 at 08:41
3

You can't use the '.aaa' as your key because Mongo uses the dot to refer to nested documents.

If you want to have the key look like a dot, you can use a unicode equivalent like \u002E:

>>> d = {'\u002Eaaa' : '\u002Ebbb'}    

However, I'd suggest your approach of just choosing another character and accepting it as a "limitation" of the platform.