meteor-mongo-minimongo について
Meteor 開発者向けの Mongo と Minimongo のガイドです。サーバーとクライアントの API の違い、非同期操作、インデックス、リアクティブデータのドライバー選択を説明します。
主な機能
- 01サーバーとクライアントの API の使い分け
- 02非同期 Mongo 操作
- 03ページングクエリのインデックス作成
- 04Change Streams、oplog、ポーリングの選択
- 05クエリやソートでの照合順序
活用シーン
- 01クライアントとサーバーで共有するクエリの作成
- 02大きなクエリのページングとインデックス設定
- 03リアクティブドライバー選択の調査
- 04大文字小文字を区別しないクエリの実装
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ meteor/ agent-skills --skill meteor-mongo-minimongoインストール後、Claude Code で/meteor-mongo-minimongoを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/eval-cases.mdselectors-modifiers.mdserver-vs-client.md詳細
Mongo と Minimongo
Meteor は、1 つのコードベースで Mongo API の 2 つの実装を提供しています。サーバーは非同期ドライバーを通じて MongoDB と通信します。クライアントでは Minimongo が動作します。これは、サブスクリプションから送信されたドキュメントを保持する、メモリー内で同期的に動作する Mongo エミュレーターです。
判断の流れ
- このコードはどこで実行されますか?
- サーバー専用:
await Collection.*Async(...)を使用します。 - クライアント専用:
Collection.*(...)を同期的に使用します。 - アイソモーフィック(共有コード内の
import):await Collection.*Async(...)を使用します。 クライアントでは処理はローカルで行われますが、引き続き Promise ベースです。サーバーでは Mongo と通信します。
- サーバー専用:
- クエリで 1 ページ分を超えるドキュメントを選択しますか?
{ limit, skip }と、セレクターに合致するインデックスを追加します。 - クライアントでパブリケーションから読み取っていますか?
awaitを付けずにfind().fetch()(同期)を使用します。データはすでにローカルにあります。
サーバーでの読み取り
const doc = await Posts.findOneAsync(id);
const list = await Posts.find({ ownerId }, {
fields: { title: 1 }, sort: { createdAt: -1 }, limit: 50,
}).fetchAsync();
const count = await Posts.find({ ownerId }).countAsync();
サーバーでの書き込み
const _id = await Posts.insertAsync({ title, ownerId });
await Posts.updateAsync({ _id }, { $set: { title } });
await Posts.removeAsync({ _id });
クライアントでの読み取り(Minimongo)
非同期 API はアイソモーフィックです。同じ行をサーバーでも動作させるため、共有コードでは非同期 API を優先してください。
const doc = await Posts.findOneAsync(id); // works in shared/client/server
const list = await Posts.find({ ownerId }).fetchAsync();
クライアントでは、処理はメモリー内の Minimongo から読み取りますが、非同期 API は引き続き実際の Promise を返します。await の後のコードは、後続のマイクロタスクで再開されます。同期 API もクライアント側で使用できますが、クライアント側に限られます。
const doc = Posts.findOne(id); // client-only
const list = Posts.find({ ownerId }).fetch(); // client-only
呼び出し元のスコープが本来同期的で、await を強制するとレンダリング処理まで非同期になってしまう場合は、同期 API を選びます。よくあるケースは次のとおりです。
- リアクティブデータを使用する React のレンダー関数とフック。
- Blaze テンプレートヘルパー。
- Tracker の autorun。
ファイルがサーバーでも実行される可能性がある場合や、含まれる関数がすでに async の場合は、非同期 API(findOneAsync、fetchAsync)を選びます。
インデックス
インデックスはサーバー側で作成します。アプリの起動時に作成してください。
import { Meteor } from "meteor/meteor";
import { Posts } from "/imports/api/posts";
Meteor.startup(async () => {
await Posts.createIndexAsync({ ownerId: 1, createdAt: -1 });
await Posts.createIndexAsync({ slug: 1 }, { unique: true });
});
複合インデックスのキー順は、等価フィルター、ソートフィールド、範囲フィルター、および利用可能なインデックスプレフィックスを考慮して選びます。等価セレクター内の JavaScript のプロパティ順は、インデックスと一致している必要はありません。Mongo シェル(meteor mongo)で db.posts.find(...).explain("executionStats") を実行し、選択されたプランを確認してください。
リアクティビティのソース:oplog または Change Streams
コアドライバーの境界はリリースごとに異なります。
| Meteor | リアクティブな動作 |
|---|---|
| 3.0 から 3.4 | MONGO_OPLOG_URL が設定されている場合は oplog を使用し、設定されていない場合はポーリングします。コアの Change Streams とリアクティビティ順序の設定は利用できません。 |
| 3.5+ | 以下のデフォルト順序で、クエリごとにドライバーを選択します。 |
Meteor 3.5+ のデフォルトは次のとおりです。
changeStreams -> oplog -> polling
Change Streams を使用するには、レプリカセットまたはシャーディングされたクラスター上の MongoDB 6+、順序なしのオブザーバー、skip または limit を指定しないこと、Minimongo でコンパイル可能なセレクターが必要です。
条件を満たさないクエリは、設定された次のドライバーにフォールバックします。oplog は MONGO_OPLOG_URL が設定されている場合にのみ利用できます。
ベータ版の beta.3 に含まれる [email protected] で検証した Meteor 3.6 では、Change Streams に対して $where/$near セレクターも対象外になります(RC では [email protected] に解決されます)。ライブイベントは、Minimongo で MongoDB のセマンティクスに基づいて再照合できません。oplog でもこれらのセレクターは対象外になるため、利用可能なポーリングへのフォールバックを確認してください。Minimongo と互換性のないプロジェクションにもフォールバックが必要です。MongoDB がサポートしていても Minimongo が拒否するプロジェクションは、ドライバーの境界であり、パブリケーションやスキーマを書き換える理由にはなりません。より広範な変更を提案する前に、フォールバックを確認してください。初回とライブの結果をテストしてください。Change Streams を強制するためだけに、セレクター、プロジェクション、ページネーションを取り除かないでください。以前の 3.5/beta.1 パッケージでは、$where/$near に対して誤ったドライバーが選択されることがあります。制約のあるリリースを使用している場合は、サポート対象のポーリング設定、または許可された互換性のあるアップグレードを使用し、該当するクエリを再実行してください。
Meteor 3.5+ では、アプリ全体の順序を METEOR_REACTIVITY_ORDER=oplog,polling で上書きするか、次のように設定します。
{
"packages": {
"mongo": {
"reactivity": ["oplog", "polling"]
}
}
}
Meteor 3.5+ では、disable-oplog パッケージによって oplog のステップのみが削除されます。Change Streams は無効になりません。ポーリングを強制するには reactivity: ["polling"] を使用してください。Meteor 3.0 から 3.4 では、これらの設定を追加せず、先にアップグレードしてください。
コアの Change Streams でオブザーバーイベントが重複したり、ログインが断続的に切断されたりする場合は、クエリを書き換えたりリアクティビティを無効にしたりする前に、解決された mongo のバージョンを確認してください。[email protected](Meteor 3.5.2)では、因果関係のあるプライマリスナップショットですでにカバーされたイベントの再生が修正されています。それ以前の 3.5 パッケージにはこの修正がありません。アップグレードして、問題が発生する一連の操作を再実行してください。これはドライバーの適格性を変えるものではなく、タイムスタンプに基づいて任意のアプリケーションイベントを破棄する根拠にもなりません。問題が続く場合は、オブザーバーの順序を記録してください。原因が不明な場合は meteor-debugging を使用してください。
照合順序(Meteor 3.5+)
Mongo と Minimongo の両方で、ロケールを考慮したセレクターや大文字小文字を区別しないセレクターおよびソートには collation を使用してください。サーバークエリは、同じ照合順序で作成したインデックスを使用してください。
const collation = { locale: "en", strength: 2 };
const users = await Users.find(
{ email: "[email protected]" },
{ collation },
).fetchAsync();
await Users.createIndexAsync({ email: 1 }, { collation });
Minimongo は locale、1 から 3 までの strength、caseLevel、numericOrdering、caseFirst をサポートします。その他の Mongo の照合オプションはサーバー専用であり、Minimongo では無視されます。
アンチパターン
- サーバーで同期 Mongo を使用する。Meteor 3 では削除されています。
- 共有コードで同期 Mongo(
findOne、insert、update、remove)を使用する。ファイルがサーバーでインポートされた時点で動作しなくなります。 - サーバーで上限のない
findを使う。常にlimitを指定してください。 - パブリッシュ時に
fieldsプロジェクションを忘れる。常にプロジェクションを指定してください。 - 非同期 Minimongo API がインラインで再開されると思い込む。基盤の読み取りはローカルですが、Promise を返します。
関連項目
references/server-vs-client.mdreferences/selectors-modifiers.mdreferences/eval-cases.md