meteor-mongo-minimongo

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Mongo and Minimongo

Mongo与Minimongo

Meteor ships two implementations of the Mongo API in one codebase. The server talks to MongoDB through an async driver. The client runs Minimongo, an in-memory synchronous Mongo emulator that holds the documents that subscriptions have shipped.
Meteor在一个代码库中提供了两种Mongo API实现。服务器通过异步驱动连接MongoDB。客户端运行Minimongo,这是一个内存中的同步Mongo模拟器,用于存储订阅推送的文档。

Decision flow

决策流程

  1. Where does this code run?
    • Server-only: use
      await Collection.*Async(...)
      .
    • Client-only: use
      Collection.*(...)
      synchronously.
    • Isomorphic (
      import
      in shared code): use
      await Collection.*Async(...)
      . On the client the work is local but still Promise-based; on the server it talks to Mongo.
  2. Does the query select more than a page of documents? Add
    { limit, skip }
    and an index that matches the selector.
  3. Are you reading from a publication on the client? Use
    find().fetch()
    (sync) without
    await
    . The data is already local.
  1. 代码运行位置?
    • 仅服务器端:使用
      await Collection.*Async(...)
    • 仅客户端:同步使用
      Collection.*(...)
    • 同构代码(在共享代码中通过
      import
      引入):使用
      await Collection.*Async(...)
      。客户端的操作是本地执行,但仍基于Promise;服务器端则直接与Mongo交互。
  2. 查询是否选取超过一页的文档?添加
    { limit, skip }
    以及与选择器匹配的索引。
  3. 是否在客户端从发布中读取数据?使用
    find().fetch()
    (同步),无需
    await
    。数据已存储在本地。

Server reads

服务器端读取

javascript
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();
javascript
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();

Server writes

服务器端写入

javascript
const _id = await Posts.insertAsync({ title, ownerId });
await Posts.updateAsync({ _id }, { $set: { title } });
await Posts.removeAsync({ _id });
javascript
const _id = await Posts.insertAsync({ title, ownerId });
await Posts.updateAsync({ _id }, { $set: { title } });
await Posts.removeAsync({ _id });

Client reads (Minimongo)

客户端读取(Minimongo)

The async API is isomorphic. Prefer it in shared code so the same line works on the server.
javascript
const doc = await Posts.findOneAsync(id);                 // works in shared/client/server
const list = await Posts.find({ ownerId }).fetchAsync();
On the client, the operation reads in-memory Minimongo but the async API still returns a real Promise. Code after
await
resumes in a later microtask. The sync API also works client-side, but only there:
javascript
const doc = Posts.findOne(id);                            // client-only
const list = Posts.find({ ownerId }).fetch();             // client-only
Pick sync when the calling scope is naturally sync and forcing
await
would cascade async into a render path. Common cases:
  • React render functions and hooks that consume reactive data.
  • Blaze template helpers.
  • Tracker autoruns.
Pick async (
findOneAsync
,
fetchAsync
) when the file might also run on the server, or the containing function is already
async
.
异步API是同构的。在共享代码中优先使用,以便同一代码行可在服务器端运行。
javascript
const doc = await Posts.findOneAsync(id);                 // 可在共享/客户端/服务器端运行
const list = await Posts.find({ ownerId }).fetchAsync();
在客户端,操作读取内存中的Minimongo数据,但异步API仍会返回真实的Promise。
await
之后的代码会在后续微任务中恢复执行。同步API也可在客户端使用,但仅限客户端:
javascript
const doc = Posts.findOne(id);                            // 仅限客户端
const list = Posts.find({ ownerId }).fetch();             // 仅限客户端
当调用环境本身是同步的,强制使用
await
会将异步逻辑渗透到渲染路径时,选择同步API。常见场景:
  • React渲染函数和消费响应式数据的hooks。
  • Blaze模板助手。
  • Tracker自动运行函数。
当文件可能同时在服务器端运行,或包含函数已为
async
时,选择异步API(
findOneAsync
fetchAsync
)。

Indexes

索引

Indexes are server-side. Create them on app startup:
javascript
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 });
});
Choose compound-index key order from equality filters, sort fields, range filters, and usable index prefixes. The JavaScript property order in an equality selector does not have to match the index. Verify the chosen plan in the Mongo shell (
meteor mongo
) with
db.posts.find(...).explain("executionStats")
.
索引是服务器端的。在应用启动时创建:
javascript
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 shell(
meteor mongo
)中使用
db.posts.find(...).explain("executionStats")
验证所选执行计划。

Reactivity source: oplog or change streams

响应式数据源:oplog或change streams

The core driver boundary is release-specific:
MeteorReactive behavior
3.0 through 3.4Uses oplog when
MONGO_OPLOG_URL
is configured; otherwise polling. Core change streams and reactivity-order settings are unavailable.
3.5+Chooses a driver per query in the default order below.
Meteor 3.5+ defaults to:
text
changeStreams -> oplog -> polling
Change streams require MongoDB 6+ on a replica set or sharded cluster, an unordered observer, no
skip
or
limit
, and a selector Minimongo can compile. An ineligible query falls through to the next configured driver. Oplog is available only when
MONGO_OPLOG_URL
is configured.
On Meteor 3.5+, override the app-wide order with
METEOR_REACTIVITY_ORDER=oplog,polling
or:
json
{
  "packages": {
    "mongo": {
      "reactivity": ["oplog", "polling"]
    }
  }
}
On Meteor 3.5+, the
disable-oplog
package removes only the oplog step. It does not disable change streams. Use
reactivity: ["polling"]
to force polling. On Meteor 3.0 through 3.4, do not add these settings; upgrade first.
核心驱动边界因版本而异:
Meteor响应式行为
3.0 至 3.4配置
MONGO_OPLOG_URL
时使用oplog;否则使用轮询。核心change streams和响应式顺序设置不可用。
3.5+按以下默认顺序为每个查询选择驱动。
Meteor 3.5+默认顺序:
text
changeStreams -> oplog -> polling
Change streams要求MongoDB 6+运行在副本集或分片集群上,使用无序观察者,无
skip
limit
,且选择器可被Minimongo编译。不符合条件的查询会自动切换到下一个配置的驱动。仅当配置
MONGO_OPLOG_URL
时,oplog才可用。
在Meteor 3.5+上,可通过
METEOR_REACTIVITY_ORDER=oplog,polling
或以下配置覆盖应用级顺序:
json
{
  "packages": {
    "mongo": {
      "reactivity": ["oplog", "polling"]
    }
  }
}
在Meteor 3.5+上,
disable-oplog
包仅移除oplog步骤,不会禁用change streams。使用
reactivity: ["polling"]
强制使用轮询。在Meteor 3.0至3.4版本中,请勿添加这些设置,建议先升级版本。

Collation (Meteor 3.5+)

排序规则(Meteor 3.5+)

Use
collation
for locale-aware or case-insensitive selectors and sorting on both Mongo and Minimongo. Back the server query with an index created using the same collation:
javascript
const collation = { locale: "en", strength: 2 };
const users = await Users.find(
  { email: "Alice@Example.COM" },
  { collation },
).fetchAsync();

await Users.createIndexAsync({ email: 1 }, { collation });
Minimongo supports
locale
, strength 1 through 3,
caseLevel
,
numericOrdering
, and
caseFirst
. Other Mongo collation options are server-only and are ignored by Minimongo.
在Mongo和Minimongo上,使用
collation
实现支持区域设置或大小写不敏感的选择器与排序。服务器端查询需搭配使用相同排序规则创建的索引:
javascript
const collation = { locale: "en", strength: 2 };
const users = await Users.find(
  { email: "Alice@Example.COM" },
  { collation },
).fetchAsync();

await Users.createIndexAsync({ email: 1 }, { collation });
Minimongo支持
locale
、强度1至3、
caseLevel
numericOrdering
caseFirst
。其他Mongo排序规则选项仅在服务器端可用,会被Minimongo忽略。

Anti-patterns

反模式

  • Use sync Mongo on the server. Removed in Meteor 3.
  • Use sync Mongo (
    findOne
    ,
    insert
    ,
    update
    ,
    remove
    ) in shared code. Breaks the moment the file is imported on the server.
  • Unbounded
    find
    on the server. Always
    limit
    .
  • Forget
    fields
    projection when publishing. Always project.
  • Assume the async Minimongo API resumes inline. It returns a Promise even though the underlying read is local.
  • 在服务器端使用同步Mongo。Meteor 3已移除该功能。
  • 在共享代码中使用同步Mongo(
    findOne
    insert
    update
    remove
    )。一旦文件在服务器端引入,代码会崩溃。
  • 在服务器端使用无限制的
    find
    。始终添加
    limit
  • 发布时忘记使用
    fields
    投影。始终添加投影。
  • 假设Minimongo异步API会立即恢复执行。即使底层读取是本地操作,它仍会返回Promise。

See also

另请参阅

  • references/server-vs-client.md
  • references/selectors-modifiers.md
  • references/eval-cases.md
  • references/server-vs-client.md
  • references/selectors-modifiers.md
  • references/eval-cases.md