午前2時のログ・パニック洗練されたリアルタイム通知機能をデプロイしたばかりだとします。机上では、すべてが完璧に見えました。しかし、サービスがデータベースにアクセスした瞬間、ログにこのエラーが溢れ出します:
MongoServerError: The $changeStream stage is only supported on replica sets or sharded clusters
これは、ローカル環境やテストサーバーがおそらくスタンドアロンのMongoDBインスタンスを実行しているために発生します。スタンドアロン・インスタンスは多くのインストーラーでデフォルト設定されていますが、これらにはOplog(オペレーションログ)がありません。Change Streamsはデータのイベントをブロードキャストするために完全にOplogに依存しているため、これがないと動作しません。
クイックフィックス(TL;DR)スタンドアロンのMongoDBをシングルノードのレプリカセットに変換する必要があります。将来的に2台目のサーバーを追加する予定がなくても、MongoDBでChange Streamsを有効にするにはレプリケーション機構をアクティブにする必要があります。このプロセスは通常60秒以内に完了します。
--replSetフラグを付けてmongodプロセスを再起動します:mongod --replSet rs0-mongoshを開き、次を実行します:rs.initiate()## なぜこれが発生するのかmacOS (Homebrew)、Windows、Ubuntuでの標準的なインストールでは、MongoDBは単一の独立したプロセスとして起動します。これにより、Oplogの作成をスキップすることでディスク容量を約5%節約できます。しかし、Change StreamsはOplogを「テイル(末尾監視)」することで動作します。Oplogがなければ、ストリームも存在しません。レプリケーションをオンにすることで、すべての書き込み操作を非表示のコレクションに記録するようMongoDBに指示し、Change Streamがそれを監視できるようになります。
ローカルインストールの修正Dockerを使用せず、マシンに直接MongoDBをインストールした場合は、以下の手順に従ってください。
1. 設定の更新mongod.confファイルを開きます。Appleシリコン搭載のMacでHomebrewを使用した場合は、通常/opt/homebrew/etc/mongod.confにあります。Linuxの場合は/etc/mongod.confを確認してください。以下の2行を追加します:
replication:
replSetName: "rs0"
2. データベースの再起動新しい設定を適用するために、サービスを再起動します。
# macOSユーザーの場合
brew services restart mongodb-community
# Linuxユーザーの場合
sudo systemctl restart mongod
3. レプリカセットの有効化mongoshと入力してMongoDBシェルに入ります。初期化コマンドを実行します:
rs.initiate()
3〜5秒待ちます。コマンドプロンプトがtest>からrs0 [direct: primary] test>に変わります。これで、シングルノードのレプリカセットが実行されました。
Docker Compose環境の修正mongo:latestのような標準のDockerイメージはスタンドアロンモードで起動します。開発ワークフローでこれを解決するには、初期化を自動的に処理するdocker-compose.yml設定を使用します。これにより、ボリュームを削除するたびに手動でrs.initiate()を実行する手間が省けます。
services:
mongo:
image: mongo:6.0
command: ["--replSet", "rs0", "--bind_ip_all"]
ports:
- "27017:27017"
healthcheck:
test: "mongosh --eval 'rs.initiate()' || exit 0"
interval: 10s
timeout: 5s
retries: 5
ヘルスチェック内の|| exit 0に注目してください。これにより、すでに初期化済みのデータベースに対してrs.initiate()が呼び出された場合に、コンテナーがエラーを報告するのを防ぎます。
修正の確認修正のテストは簡単です。watch.jsという名前のファイルを作成し、以下のNode.jsスニペットを貼り付けます:
const { MongoClient } = require('mongodb');
async function run() {
const uri = 'mongodb://localhost:27017/?replicaSet=rs0';
const client = new MongoClient(uri);
await client.connect();
console.log('Connected. Watching testdb.orders...');
const stream = client.db('testdb').collection('orders').watch();
stream.on('change', (change) => {
console.log('Event detected:', change.operationType, change.fullDocument);
});
}
run().catch(console.error);
node watch.jsを実行します。GUIまたはシェルを使用して、ordersコレクションにドキュメントを挿入します。ターミナルにイベントが表示されれば、エラーは正式に解決されました。

