Docs Home → アプリケーションの開発 → Python ドライバー → PyMongo
トラブルシューティング
このページでは、MongoDB で PyMongo を使用する際に発生する一般的な問題の解決策を見つけることができます。
接続
サーバーはワイヤバージョン X を報告、PyMongo は Y が必要です
MongoDB Server v 3.4またはそれ以前のバージョンに接続しようとすると、PyMongo は次のエラーを発生させる可能性があります。
pymongo.errors.ConfigurationError: Server at localhost:27017 reports wire version 5, but this version of PyMongo requires at least 6 (MongoDB 3.6).
これは、接続先のサーバーに対してドライバーのバージョンが新しすぎる場合に発生します。 この問題を解決するには、MongoDB の配置を v 3.6以降にアップグレードするか、MongoDB Server v 2.6以降をサポートする PyMongo v 3 .x にダウングレードします。
AutoReconnect
AutoReconnect
例外は、 フェイルオーバーが発生したことを示します。 これは、PyMongo がレプリカセットの元のプライマリ メンバーへの接続を失い、最後の操作が失敗した可能性があることを意味します。
このエラーが発生すると、PyMongo は自動的に後続の操作のために新しいプライマリ メンバーを検索しようとします。 エラーを処理するには、アプリケーションは次のいずれかのアクションを実行する必要があります。
失敗した可能性のある操作を再試行する
操作が失敗した可能性を認識しながら実行を続行
重要
PyMongo は、レプリカセットが新しいプライマリ メンバーを選出するまで、すべての操作でAutoReconnect
エラーを発生させます。
トンネルを使用して PyMongo から MongoDB にアクセスする際のタイムアウト
SSH トンネル経由で MongoDB レプリカセットに接続しようとすると、次のエラーが表示されます。
File "/Library/Python/2.7/site-packages/pymongo/collection.py", line 1560, in count return self._count(cmd, collation, session) File "/Library/Python/2.7/site-packages/pymongo/collection.py", line 1504, in _count with self._socket_for_reads() as (connection, slave_ok): File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 17, in __enter__ return self.gen.next() File "/Library/Python/2.7/site-packages/pymongo/mongo_client.py", line 982, in _socket_for_reads server = topology.select_server(read_preference) File "/Library/Python/2.7/site-packages/pymongo/topology.py", line 224, in select_server address)) File "/Library/Python/2.7/site-packages/pymongo/topology.py", line 183, in select_servers selector, server_timeout, address) File "/Library/Python/2.7/site-packages/pymongo/topology.py", line 199, in _select_servers_loop self._error_message(selector)) pymongo.errors.ServerSelectionTimeoutError: localhost:27017: timed out
これは、PyMongo が他のレプリカセット ノードのアドレスとポートを含むisMaster
コマンドの応答を使用してレプリカセット ノードを検出するために発生します。 ただし、SSH トンネル経由でこれらのアドレスとポートにアクセスすることはできません。
代わりに、SSH トンネルでdirectConnection=True
オプションを使用することで、単一の MongoDB ノードに直接接続できます。
読み取り操作と書込み操作
AutoReconnect
エラー
読み込み設定(read preference)でtag-sets
を指定しており、MongoDB が指定されたタグを持つレプリカセット メンバーを見つけられない場合は、このエラーが表示されます。 このエラーを回避するには、タグセット リストの最後に空の辞書( {}
)を含めます。 これにより、一致するタグが見つからない場合は、読み取り参照モードに一致するノードから読み取るように PyMongo に指示します。
非推奨警告: カウントは非推奨
PyMongo はcount()
メソッドのサポートを終了しました。 代わりに、 Collection
クラスのcount_documents()
メソッドを使用します。
重要
count_documents()
メソッドはCollection
クラスに属します。 Cursor.count_documents()
を呼び出しようとすると、PyMongo は次のエラーを発生させます。
Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Cursor' object has no attribute 'count'
MongoClient が ConfigurationError に失敗
無効なキーワード引数名を指定すると、ドライバーはこのエラーを発生させます。
指定したキーワード引数が存在し、正しくスペルされていることを確認します。
Web アプリケーションで ObjectId を使用してドキュメントをクエリしても結果がない
次のコード例に示すように、ウェブ アプリケーションでは URL でドキュメントの ObjectId をエンコードするのが一般的です。
"/posts/50b3bda58a02fb9a84d8991e"
ウェブ フレームワークは、URL の ObjectId 部分を string としてリクエスト ハンドラーに渡します。 string をfind_one()
メソッドに渡す前に、 ObjectId
インスタンスに変換する必要があります。
次のコード例は、 Flask でこの変換を実行する方法を示しています。 アプリケーション。プロセスは他のウェブ フレームワークでも同様です。
from pymongo import MongoClient from bson.objectid import ObjectId from flask import Flask, render_template client = MongoClient() app = Flask(__name__) def show_post(_id): # NOTE!: converting _id from string to ObjectId before passing to find_one post = client.db.posts.find_one({'_id': ObjectId(_id)}) return render_template('post.html', post=post) if __name__ == "__main__": app.run()
クエリは shell では機能しますが、PyMongo では機能しません
常に最初である_id
フィールドの後は、BSON ドキュメント内のキーと値のペアは任意の順序にすることができます。 次のコード例のフィールド「b」と「a」に示されているように、 mongo
shell は、データの読み取りと書き込み中にキーの順序を保持します。
// mongo shell db.collection.insertOne( { "_id" : 1, "subdocument" : { "b" : 1, "a" : 1 } } ) // Returns: WriteResult({ "nInserted" : 1 }) db.collection.findOne() // Returns: { "_id" : 1, "subdocument" : { "b" : 1, "a" : 1 } }
PyMongo はデフォルトで BSON ドキュメントを Python 辞書として表現し、辞書内のキーの順序は定義されていません。 Python では、最初に "a" キーで宣言された辞書は、最初に "b" キーを使用して宣言された辞書と同じです。 次の例では、 print
ステートメントでの順序に関係なく、キーが同じ順序で表示されます。
print({'a': 1.0, 'b': 1.0}) # Returns: {'a': 1.0, 'b': 1.0} print({'b': 1.0, 'a': 1.0}) # Returns: {'a': 1.0, 'b': 1.0}
同様に、Python 辞書では、BSON に保存される順序でキーが表示されない場合があります。 次の例は、前の例に挿入されたドキュメントを印刷した結果を示しています。
print(collection.find_one()) # Returns: {'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
BSON を読み取るときにキーの順序を保持するには、キーの順序を記憶する辞書であるSON
クラスを使用します。
次のコード例は、 SON
クラスを使用するように構成されたコレクションを作成する方法を示しています。
from bson import CodecOptions, SON opts = CodecOptions(document_class=SON) CodecOptions(document_class=...SON..., tz_aware=False, uuid_representation=UuidRepresentation.UNSPECIFIED, unicode_decode_error_handler='strict', tzinfo=None, type_registry=TypeRegistry(type_codecs=[], fallback_encoder=None), datetime_conversion=DatetimeConversion.DATETIME) collection_son = collection.with_options(codec_options=opts)
前述のサブドキュメントが見つかると、ドライバーはSON
オブジェクトを含むクエリ結果を表し、キーの順序を保持します。
print(collection_son.find_one())
SON([('_id', 1.0), ('subdocument', SON([('b', 1.0), ('a', 1.0)]))])
サブドキュメントの実際のストレージ 配置が表示されるようになりました。"b" は "a" の前にあります。
Because a Python dictionary's key order is not defined, you cannot predict how it will be serialized to BSON. ただし、MongoDB では、キーの順序が同じ場合にのみ、サブドキュメントが と等しいと見なされます。 Python 辞書を使用してサブドキュメントをクエリする場合、一致しない可能性があります。
collection.find_one({'subdocument': {'b': 1.0, 'a': 1.0}}) is None
True
Python は 2 つの辞書を同じと見なすため、クエリ内でキーの順序を入れ替えても、違いはありません。
collection.find_one({'subdocument': {'b': 1.0, 'a': 1.0}}) is None
True
これは 2 つの方法で解決できます。 まず、サブドキュメントを フィールドごとに照合します。
collection.find_one({'subdocument.a': 1.0, 'subdocument.b': 1.0})
{'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
クエリは、Python で指定する順序や BSON に保存される順序に関係なく、"a" が1.0 1.0で、かつ "b" を持つ 任意の サブドキュメントと一致します。 このクエリは、「a」と「b」以外の追加のキーを持つサブドキュメントも一致するようになりましたが、以前のクエリでは完全一致が必要でした。
2 つ目の解決策は、 ~bson.son.SON
オブジェクトを使用してキーの順序を指定することです。
query = {'subdocument': SON([('b', 1.0), ('a', 1.0)])} collection.find_one(query)
{'_id': 1.0, 'subdocument': {'a': 1.0, 'b': 1.0}}
ドライバーは、~bson.son.SON
を BSON に直列化し、それをクエリとして使用する場合に、 を作成したときに使用したキーの順序を保持します。 したがって、 コレクション内のサブドキュメントと完全に一致するサブドキュメントを作成できます。
注意
サブドキュメントの一致の詳細については、 ドキュメントの 「埋め込み/ネストされたドキュメントへのクエリ」MongoDB Server ガイドを参照してください。
Cursors
「カーソル」オブジェクトには属性「_Cursor_killed」がありません
PyMongo v 3.8またはそれ以前のバージョンでは、 Cursor
コンストラクターに無効な引数を指定するとTypeError
とAttributeError
が発生します。 AttributeError
は関係ありませんが、 TypeError
には次の例に示すようにデバッグ情報が含まれています。
Exception ignored in: <function Cursor.__del__ at 0x1048129d8> ... AttributeError: 'Cursor' object has no attribute '_Cursor__killed' ... TypeError: __init__() got an unexpected keyword argument '<argument>'
これを修正するには、適切なキーワード引数を指定していることを確認してください。 また、PyMongo v 3.9以降にアップグレードすることで、関連性のないエラーも排除されます。
" CursorNotFoundカーソル ID はサーバーで有効ではありません"
MongoDB のカーソルは、サーバー上で操作が実行されずに長時間開いていると、サーバー上でタイムアウトすることがあります。 これにより、カーソルを反復処理しようとすると、 CursorNotFound
の例外が発生する可能性があります。
プロジェクション
<field>「インクルージョンプロジェクションのフィールド「フィールド」を除外できません」
単一のプロジェクションにフィールドを含め、除外しようとすると、ドライバーはこのメッセージとともにOperationFailure
を返します。 プロジェクションが、含めるフィールドまたは除外するフィールドのみを指定していることを確認します。
Indexes
DuplicateKeyException
一意なインデックスに違反する重複値を保存する書込み操作を実行すると、ドライバーはDuplicateKeyException
を発生させ、MongoDB は次のようなエラーを返します。
E11000 duplicate key error index
Data Formats
ValueError: UuidRepresentation.UNSpecIFIED を使用してネイティブ uuid.UUID をエンコードできません
このエラーは、次のコード例に示すように、UUID 表現がUNSPECIFIED
の場合に、ネイティブUUID
オブジェクトをBinary
オブジェクトにエンコードしようとした結果です。
unspecified_collection.insert_one({'_id': 'bar', 'uuid': uuid4()}) Traceback (most recent call last): ... ValueError: cannot encode native uuid.UUID with UuidRepresentation.UNSPECIFIED. UUIDs can be manually converted to bson.Binary instances using bson.Binary.from_uuid() or a different UuidRepresentation can be configured. See the documentation for UuidRepresentation for more information.
代わりに、次の例に示すように、 Binary.from_uuid()
メソッドを使用してネイティブ UUID をBinary
オブジェクトに明示的に変換する必要があります。
explicit_binary = Binary.from_uuid(uuid4(), UuidRepresentation.STANDARD) unspec_collection.insert_one({'_id': 'bar', 'uuid': explicit_binary})
別の言語のドライバーによって保存された日付をデコードするときにオーバーフローエラーが発生する
PyMongo は BSON datetime
値を Python のdatetime.datetime
クラスのインスタンスにデコードします。 datetime.datetime
のインスタンスは、 datetime.MINYEAR
( 1 )からdatetime.MAXYEAR
( 9999 )までの年に制限されています。 一部の MongoDB ドライバーは、 datetime.datetime
でサポートされている値より大幅に外側の年値を持つ BSON 日時を保存できます。
この問題を回避する方法がいくつかあります。 PyMongo 4.3以降、 bson.decode
は 4 つの方法のいずれかで BSON datetime
値を復号化できます。 変換方法は、 ~bson.codec_options.CodecOptions
のdatetime_conversion
パラメータを使用して指定できます。
デフォルトの変換オプションは~bson.codec_options.DatetimeConversion.DATETIME
です。これにより、値がdatetime.datetime
としてデコードされ、範囲外の日付に対して~builtin.OverflowError
が発生できるようになります。 ~bson.codec_options.DatetimeConversion.DATETIME_AUTO
はこの動作を変更して、表現が範囲外の場合には代わりに~bson.datetime_ms.DatetimeMS
を返し、以前のように~datetime.datetime
オブジェクトを返します。
from datetime import datetime from bson.datetime_ms import DatetimeMS from bson.codec_options import DatetimeConversion from pymongo import MongoClient client = MongoClient(datetime_conversion=DatetimeConversion.DATETIME_AUTO) client.db.collection.insert_one({"x": datetime(1970, 1, 1)}) client.db.collection.insert_one({"x": DatetimeMS(2**62)}) for x in client.db.collection.find(): print(x)
{'_id': ObjectId('...'), 'x': datetime.datetime(1970, 1, 1, 0, 0)} {'_id': ObjectId('...'), 'x': DatetimeMS(4611686018427387904)}
その他のオプションについては、 DatetimeConversion の API ドキュメントを参照してください クラス。
datetime_conversion
の設定に関係のないもう 1 つのオプションは、 ~datetime.datetime
でサポートされている範囲外のドキュメント値をフィルタリングで除外することです。
from datetime import datetime coll = client.test.dates cur = coll.find({'dt': {'$gte': datetime.min, '$lte': datetime.max}})
datetime
の値が必要ない場合は、そのフィールドのみをフィルタリングで除外できます。
cur = coll.find({}, projection={'dt': False})
TLS
CERTTICATE_VERIFY_FAILED
次のようなエラー メッセージは、OpenSSL がサーバーの証明書を検証できなかったことを意味します。
[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
これは、OpenSSL がシステムのルート証明書にアクセスできないか、証明書が古くなっているために多く発生します。
Linux を使用する場合は、Linux ベンダーから最新のルート証明書の更新がインストールされていることを確認してください。
macOS を使用しており、python.org からダウンロードした Python v 3.7以降を実行している場合は、 ルート証明書をインストールするには、次のコマンドを実行します。
open "/Applications/Python <YOUR PYTHON VERSION>/Install Certificates.command"
Tip
この問題の詳細については、 Python の問題29065 を参照してください。
port-pypy を使用する場合は、OpenSSL にルート証明書を見つける場所を指示するために環境変数を設定する必要がある場合があります。 次のコード例は、 認証モジュール をインストールする方法を示しています から Pypi に接続し、SSL_CERT_FILE
環境変数をエクスポートします。
$ pypy -m pip install certifi $ export SSL_CERT_FILE=$(pypy -c "import certifi; print(certifi.where())")
Tip
この問題の詳細については、 port-pypy の問題15 を参照してください。
TLSV 1 _ALERT_PROTOCOL_VERSION
次のようなエラーメッセージが表示された場合、Python で使用される OpenSSL バージョンでは、サーバーに接続するのに十分な新しい TLS プロトコルがサポートされていないことを意味します。
[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version
業界のベストプラクティスでは、一部の MongoDB の配置で古い TLS プロトコルを無効にすることが推奨されています。また、一部の規則では、古い TLS プロトコルを無効にすることが推奨されています。 一部の配置では TLS 1.0が無効になり、他の配置では TLS 1.0および TLS 1.1が無効になる場合があります。
PyMongo が最新の TLS バージョンを使用するためにアプリケーションを変更する必要はありませんが、一部のオペレーティング システムのバージョンでは、それらをサポートするのに十分な新しい OpenSSL バージョンが提供されていない場合があります。
macOS v 10.12を使用している場合 (High Sierra)またはそれ以前の場合は、 python.org から Python をインストールします。 Homebrew、macports、または同様のソース。
Linux またはその他の macOS Unix を使用している場合は、次のコマンドを使用して OpenSSL バージョンを確認します。
openssl version
上記のコマンドで1.0.1未満のバージョン番号が表示されている場合、 TLS 1.1以降のサポートは利用できません。 新しいバージョンにアップグレードするか、OS ベンダーに解決策について問い合わせてください。
Python インタープリタの TLS バージョンを確認するには、 requests
モジュールをインストールして次のコードを実行します。
python -c "import requests; print(requests.get('https://www.howsmyssl.com/a/check', verify=False).json()['tls_version'])"
TLS 1.1以降が表示されます。
無効なステータス応答
次のようなエラー メッセージが表示された場合、証明書失効チェックに失敗したことを意味します。
[('SSL routines', 'tls_process_initial_server_flight', 'invalid status response')]
詳細については、このガイドの「 OCSP 」セクションを参照してください。
SSLV 3 _ALERT_HANDSHAKE_FAILURE
Python v 3.10以降を v 4.0より前のバージョンの MongoDB で使用する場合、 次のメッセージのようなエラーが表示される場合があります。
SSL handshake failed: localhost:27017: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997) SSL handshake failed: localhost:27017: EOF occurred in violation of protocol (_ssl.c:997)
MongoDB Server ログには、次のエラーも表示される場合があります。
2021-06-30T21:22:44.917+0100 E NETWORK [conn16] SSL: error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher
Python v で ssl モジュールに加えられた変更3.10は v 4より前の MongoDB バージョンとの互換性がない可能性があります。 0 。 この問題を解決するには、次の手順の 1 つ以上を試してください。
Python を v 3.9またはそれ以前のバージョンにダウングレード
MongoDB Server を v 4.2以降にアップグレードする
OCSPオプションを使用して PyMongo をインストールする(PyOpenSSL に依存する)
クライアント側操作タイムアウト
ServerSelectionTimeoutError
このエラーは、クライアントが指定されたタイムアウト内に操作を実行するために利用できるサーバーを見つけられなかったことを示しています。
pymongo.errors.ServerSelectionTimeoutError: No servers found yet, Timeout: -0.00202266700216569s, Topology Description: <TopologyDescription id: 63698e87cebfd22ab1bd2ae0, topology_type: Unknown, servers: [<ServerDescription ('localhost', 27017) server_type: Unknown, rtt: None>]>
ネットワークタイムアウト
このエラーは、クライアントが指定されたタイムアウト内に接続を確立できなかったこと、または操作が送信されたがサーバーが時間内に応答しなかったことを示しています。
pymongo.errors.NetworkTimeout: localhost:27017: timed out
ExecutionTimeout
このエラーは、指定されたタイムアウトを超えたため、サーバーが操作をキャンセルしたことを示している可能性があります。 PyMongo がこの例外を発生させた場合でも、サーバー上で操作が部分的に完了している可能性があります。
pymongo.errors.ExecutionTimeout: operation exceeded time limit, full error: {'ok': 0.0, 'errmsg': 'operation exceeded time limit', 'code': 50, 'codeName': 'MaxTimeMSExpired'}
また、指定されたタイムアウト内に操作を完了できなかったため、クライアントが操作をキャンセルしたことを示す場合もあります。
pymongo.errors.ExecutionTimeout: operation would exceed time limit, remaining timeout:0.00196 <= network round trip time:0.00427
WTimeoutError
このエラーは、サーバーが指定されたタイムアウト内に、指定された書込み保証 (write concern) に従って要求された書込み操作を完了できなかったことを示しています。
pymongo.errors.WTimeoutError: operation exceeded time limit, full error: {'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}
BulkWriteError
このエラーは、サーバーが指定されたタイムアウト内に、指定された書込み保証 (write concern) に従い、 メソッドまたは メソッドを完了できなかったことを示しています。insert_many()
bulk_write()
pymongo.errors.BulkWriteError: batch op errors occurred, full error: {'writeErrors': [], 'writeConcernErrors': [{'code': 50, 'codeName': 'MaxTimeMSExpired', 'errmsg': 'operation exceeded time limit', 'errInfo': {'writeConcern': {'w': 1, 'wtimeout': 0}}}], 'nInserted': 2, 'nUpserted': 0, 'nMatched': 0, 'nModified': 0, 'nRemoved': 0, 'upserted': []}
プロセスのフォーク
プロセスをフォークするとデッドロックが発生する
MongoClient
インスタンスは、接続されたサーバーの監視などのバックグラウンド タスクを実行するために複数のスレッドを生成します。 これらのスレッドは、 フォークセーフではない クラスのインスタンスによって保護されている状態を共有しますthreading.Lock
。PyMongo には、 threading.Lock
クラスまたはミューテックスを使用する他のマルチスレッド コードと同じ制限が適用されます。
これらの制限の 1 つは、 fork()
メソッドを呼び出した後にロックが使用できなくなることです。 fork()
が実行されると、ドライバーは親プロセスのすべてのロックを、親と同じ状態で子プロセスにコピーします。 親プロセスでロックされている場合は、子プロセスでもロックされます。 fork()
によって作成された子プロセスにはスレッドが 1 つしかないため、親プロセスの他のスレッドによって作成されたロックは、子プロセスでは解放されません。 子プロセスが次にこれらのロックのいずれかを取得しようとすると、デッドロックが発生します。
PyMongo バージョン4.3以降では、 os.fork()
メソッドを呼び出すと、ドライバーはos.register_at_fork()
メソッドを使用して子プロセス内のロックやその他の共有状態をリセットします。 これによりデッドロックの可能性は減りますが、PyMongo は OpenSSL などのマルチスレッド アプリケーションではフォークセーフでないライブラリに依存しています3 と getaddrinfo( )。そのため、デッドロックは引き続き発生する可能性があります。
fork 用の Linux マニュアルページ(2 ) また、次の制限も課されます。
fork()
マルチスレッド プログラムで の後、子は非同期シグナルセーフな関数のみを安全に呼び出せるようになります( シグナル安全性(7 ) を参照してください )を、 execVE(2 )を呼び出すまで。
PyMongo は非同期シグナルセーフでない関数に依存しているため、子プロセスで実行するとデッドロックやクラッシュが発生する可能性があります。
Tip
子プロセスにおけるデッドロックの例については、 Python-3406 を参照してください。 Jira の。
Pythonfork()
を使用したマルチスレッド6721 Pythonコンテキストでの ロックが発生する問題の詳細については、 の問題 を参照してください を指定します。