python MongoDB に登録時に pymongo.errors.WriteError: The dotted field...


エラー内容

以下状況で、MongoDBに登録できないエラーが発生しました。

状況

  1. XMLを取得して、python Objectに変換する
  2. 1.python Objectjson Objectに変換
  3. 2. で作成したjson ObjectMongoDB に登録

エラー出力

.virtualenvs/v3.4.3/lib/python3.4/site-packages/pymongo/helpers.py", line 301, in _check_write_command_response
    raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: The dotted field ...

原因

MongoDBのキー値の制約に依るエラーです。
Javaで自分自身が同じような問題にぶつかっていました。 .と、$が原因で落ちていたので、キー値に含まれる場合、別の文字列に変換する方向で対応しました。 $が含まれる場合は、以下のエラーが出力され落ちました。

$が含まれる場合のエラー

.virtualenvs/v3.4.3/lib/python3.4/site-packages/pymongo/helpers.py", line 301, in _check_write_command_response
    raise WriteError(error.get("errmsg"), error.get("code"), error)
pymongo.errors.WriteError: The dollar ($) prefixed field '$' in ' ...

対応

remove_dots メソッドで、辞書のキー値に含まれる.$ を別の文字列に変換するようにしました。
remove_dots の元ネタはこちら を参考にしました。
$ も変換しているので、remove_dots ではなくなっていますが、
list 内に辞書が含まれるケースもあったので、if 文を追加しています。

def remove_dots(data):
    for key in data.keys():
        if type(data[key]) is dict: data[key] = remove_dots(data[key])
        if type(data[key]) is list:
            for i, v in enumerate(data[key]):
                if type(v) is dict:
                    v = remove_dots(v)
                    data[key][i] = v

        if '.' in key:
            data[key.replace('.', '_')] = data[key]
            del data[key]
        if '$' in key:
            data[key.replace('$', '@dollar@')] = data[key]
            del data[key]
    return data

以上です。

コメント