集合
Meteor 将数据存储在集合中。要开始使用,请使用new Mongo.Collection
声明一个集合。
Mongo.Collection
摘要
集合的构造函数
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
name | 字符串 | 集合的名称。如果为 null,则创建一个未管理的(不同步的)本地集合。 | 是 |
options | 对象 | 否 |
import { Mongo } from "meteor/mongo"";
const collection = new Mongo.Collection(
"name",
options, // this param is optional
);
调用此函数类似于在传统的以 ORM(对象关系映射)为中心的框架中声明模型。它设置了一个集合(用于存储记录或“文档”的存储空间),可用于存储特定类型的信息,例如用户、帖子、分数、待办事项或与您的应用程序相关的所有内容。每个文档都是一个 EJSON 对象。它包含一个_id
属性,其值在集合中是唯一的,当您首次创建文档时,Meteor 将设置该属性。
// Common code on client and server declares a DDP-managed Mongo collection.
const Chatrooms = new Mongo.Collection("chatrooms");
const Messages = new Mongo.Collection("messages");
该函数返回一个对象,其中包含在集合中insert
文档、update
其属性和remove
它们以及find
与任意条件匹配的集合中的文档的方法。这些方法的工作方式与流行的 Mongo 数据库 API 兼容。相同的数据库 API 在客户端和服务器端都适用(见下文)。
// Return an array of my messages.
const myMessages = await Messages.find({ userId: Meteor.userId() }).fetchAsync();
// Create a new message.
await Messages.insertAsync({ text: "Hello, world!" });
// Mark my first message as important.
await Messages.updateAsync(myMessages[0]._id, { $set: { important: true } });
如果您在创建集合时传递了name
,那么您就在声明一个持久性集合——一个存储在服务器上并由所有用户看到的集合。客户端代码和服务器端代码都可以使用相同的 API 访问同一个集合。
具体来说,当您传递name
时,会发生以下情况
在服务器端(如果您未指定
connection
),会在后端 Mongo 服务器上创建具有该名称的集合。当您在服务器端对该集合调用方法时,它们会直接转换为正常的 Mongo 操作(在检查它们是否与您的访问控制规则匹配之后)。在客户端(以及在您指定
connection
的服务器端),会创建一个 Minimongo 实例。Minimongo 本质上是纯 JavaScript 中 Mongo 的内存中非持久性实现。它充当本地缓存,存储此客户端正在使用的数据库的子集。对这些集合的查询(find
)直接来自此缓存,无需与服务器通信。当您在客户端写入数据库(
insert
、update
、remove
)时,命令会立即在本地执行,同时,它也会发送到服务器并在那里执行。这是通过存根发生的,因为写入是作为方法实现的。
当在服务器端,您写入具有指定
connection
到另一个服务器的集合时,它会将相应的方法发送到另一个服务器,并从该服务器通过 DDP 接收回更改后的值。与客户端不同,它不会首先在本地执行写入操作。
危险
在 Meteor 3.x 及更高版本中,在服务器端使用insert
、update
、upsert
、remove
、findOne
将抛出错误。请改用*Async
对应项。
例如,不要使用collection.insert(doc)
,请使用collection.insertAsync(doc)
。
如果您将名称传递给仅限客户端的集合,则它不会与服务器同步,您需要使用低级发布接口(added/changed/removed
)“手动”填充集合。有关更多信息,请参阅added
。
如果您将null
作为name
传递,那么您正在创建一个本地集合。它不会与任何地方同步;它只是一个支持 Mongo 样式find
、insert
、update
和remove
操作的本地草稿。 (在客户端和服务器端,此草稿都是使用 Minimongo 实现的)。
默认情况下,Meteor 会自动将您集合中的每个文档发布到每个连接的客户端。要关闭此行为,请在您的终端中删除autopublish
软件包
meteor remove autopublish
并改为调用Meteor.publish
以指定集合的哪些部分应发布到哪些用户。
// client.js
// Create a collection called `Posts` and put a document in it. The document
// will be immediately visible in the local copy of the collection. It will be
// written to the server-side database a fraction of a second later, and a
// fraction of a second after that, it will be synchronized down to any other
// clients that are subscribed to a query that includes it (see
// `Meteor.subscribe` and `autopublish`).
const Posts = new Mongo.Collection("posts");
Posts.insert({ title: "Hello world", body: "First post" });
// Changes are visible immediately—no waiting for a round trip to the server.
assert(Posts.find().count() === 1);
// Create a temporary, local collection. It works just like any other collection
// but it doesn't send changes to the server, and it can't receive any data from
// subscriptions.
const Scratchpad = new Mongo.Collection();
for (let i = 0; i < 10; i += 1) {
Scratchpad.insert({ number: i * 2 });
}
assert(Scratchpad.find({ number: { $lt: 9 } }).count() === 5);
通常,您会在应用程序中将Mongo.Collection
对象分配给全局变量。对于每个底层 Mongo 集合,您只能创建一个Mongo.Collection
对象。
如果您为Collection
或其任何检索方法指定了transform
选项,则文档将在返回或传递给回调之前通过transform
函数传递。这允许您从其数据库表示形式添加方法或以其他方式修改集合的内容。您还可以在特定的find
、findOne
、allow
或deny
调用上指定transform
。转换函数必须返回一个对象,并且它们不能更改文档的_id
字段的值(尽管可以将其省略)。
// An animal class that takes a document in its constructor.
class Animal {
constructor(doc) {
_.extend(this, doc);
}
makeNoise() {
console.log(this.sound);
}
}
// Define a collection that uses `Animal` as its document.
const Animals = new Mongo.Collection("animals", {
transform: (doc) => new Animal(doc),
});
// Create an animal and call its `makeNoise` method.
Animals.insert({ name: "raptor", sound: "roar" });
Animals.findOne({ name: "raptor" }).makeNoise(); // Prints 'roar'
transform
函数不会以反应式方式调用。如果您想向对象添加动态变化的属性,请使用在调用时计算值的函数,而不是在transform
时计算属性。
警告
在此版本中,Minimongo 有一些限制
- 修饰符中的
$pull
只能接受某些类型的选择器。 - 不支持
findAndModify
、聚合函数以及 map/reduce。
所有这些都将在未来的版本中得到解决。有关完整的 Minimongo 发行说明,请参阅存储库中的 packages/minimongo/NOTES。
警告
Minimongo 目前没有索引。这很少成为问题,因为客户端拥有足够的数据以至于索引值得使用的情况并不常见。
在 Meteor 指南的集合文章中阅读更多关于集合以及如何使用它们的信息。
Collection.find
摘要
查找与选择器匹配的集合中的文档。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 描述要查找的文档的查询 | 否 |
options | 对象 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Mongo.Cursor */
const result = Collection.find(
MongoSelector, // this param is optional
options, // this param is optional
);
find
返回一个游标。它不会立即访问数据库或返回文档。游标提供 fetch
来返回所有匹配的文档,map
和 forEach
来迭代所有匹配的文档,以及 observeAsync
和 observeChangesAsync
来在匹配文档集发生更改时注册回调。游标还实现了 ES2015 的 迭代协议。
警告
集合游标不是查询快照。如果在调用 Collection.find
和获取游标结果之间,或在从游标获取结果期间数据库发生更改,则这些更改可能会或可能不会出现在结果集中。
游标是反应式数据源。在客户端,您第一次在反应式计算(例如模板或 autorun
)中使用 fetch
、map
或 forEach
检索游标的文档时,Meteor 将注册对底层数据的依赖关系。对集合的任何更改(更改游标中的文档)都将触发重新计算。要禁用此行为,请将 {reactive: false}
作为选项传递给 find
。
请注意,当指定 fields
时,只有对包含字段的更改才会触发 observeAsync
、observeChangesAsync
中的回调以及使用此游标的反应式计算中的失效。谨慎使用 fields
可以为不依赖于整个文档的计算提供更细粒度的反应性。
在客户端,在页面加载和从服务器获取已发布数据到达之间会有一段时间,在此期间您的客户端集合将为空。
Collection.findOne
摘要
查找与选择器匹配的第一个文档,按排序和跳过选项排序。如果未找到匹配的文档,则返回 undefined
。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 描述要查找的文档的查询 | 否 |
options | 对象 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Object */
const result = Collection.findOne(
MongoSelector, // this param is optional
options, // this param is optional
);
警告
仅限客户端。有关服务器/同构用法,请参阅 findOneAsync。
等效于 find
(selector, options).
fetch
()[0]
,其中 options.limit = 1
。
Collection.findOneAsync
摘要
查找与选择器匹配的第一个文档,按排序和跳过选项排序。如果未找到匹配的文档,则返回 undefined
。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 描述要查找的文档的查询 | 否 |
options | 对象 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Object */
const result = Collection.findOneAsync(
MongoSelector, // this param is optional
options, // this param is optional
);
findOne
的异步版本,返回一个 Promise
。
Collection.countDocuments
摘要
获取与过滤器匹配的文档数量。有关集合中所有文档的快速计数,请参阅 estimatedDocumentCount
。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 描述要计数的文档的查询 | 否 |
options | 对象 | 所有选项都列在 MongoDB 文档 中。请注意,并非所有选项都可以在客户端使用。 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Promise<number> */
const result = Collection.countDocuments(
MongoSelector, // this param is optional
options, // this param is optional
);
类似于 cursor.count
,但返回一个 Promise
。有关更快的版本,请参阅 estimatedDocumentCount
。
Collection.estimatedDocumentCount
摘要
使用集合元数据获取集合中文档数量的估计值。有关集合中文档的确切数量,请参阅 countDocuments
。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
options | 对象 | 所有选项都列在 MongoDB 文档 中。请注意,并非所有选项都可以在客户端使用。 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Promise<number> */
const result = Collection.estimatedDocumentCount(
options
);
返回一个 Promise
,该 Promise
解析为游标结果集中文档的数量。计数是一个估计值,不保证准确。
Collection.insert
摘要
在集合中插入一个文档。返回一个 promise,当解决时将返回文档的唯一 _id。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
doc | 对象 | 要插入的文档。可能还没有 _id 属性,在这种情况下,Meteor 将为您生成一个。 | 是 |
// Collection is an instance of Mongo.Collection
Collection.insert(
doc
);
警告
仅限客户端。有关服务器/同构用法,请参阅 insertAsync。
将文档添加到集合中。文档只是一个对象,其字段可以包含 EJSON 兼容数据类型的任何组合(数组、对象、数字、字符串、null
、true 和 false)。
insert
将为传递的对象生成一个唯一 ID,将其插入数据库并返回 ID。当从不受信任的客户端代码调用 insert
时,只有在通过任何适用的 allow
和 deny
规则后才允许。
在服务器端,应使用 insertAsync
,它将返回一个包含对象 ID
的 promise。
在客户端,insert
永远不会阻塞。如果您不提供回调并且插入在服务器上失败,则 Meteor 将向控制台记录警告。如果您提供回调,Meteor 将使用 error
和 result
参数调用该函数。在错误情况下,result
未定义。如果插入成功,则 error
未定义,result
是新的文档 ID。
示例
const groceriesId = Lists.insert({ name: "Groceries" });
Items.insert({ list: groceriesId, name: "Watercress" });
Items.insert({ list: groceriesId, name: "Persimmons" });
Collection.insertAsync
摘要
在集合中插入一个文档。返回其唯一的 _id。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
doc | 对象 | 要插入的文档。可能还没有 _id 属性,在这种情况下,Meteor 将为您生成一个。 | 是 |
// Collection is an instance of Mongo.Collection
/** @returns Promise */
const result = Collection.insertAsync(
doc
);
insert
的异步版本,返回一个 Promise
。
Collection.update
摘要
异步修改集合中一个或多个文档。返回匹配文档的数量。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要修改哪些文档 | 是 |
modifier | MongoModifier | 指定如何修改文档 | 是 |
options | 对象 | 否 | |
callback | 函数 | 可选。如果存在,则以错误对象作为第一个参数调用,如果无错误,则以受影响的文档数量作为第二个参数调用。 | 否 |
// Collection is an instance of Mongo.Collection
Collection.update(
MongoSelector,
MongoModifier,
options, // this param is optional
() => {}, // this param is optional
);
警告
仅限客户端。有关服务器/同构用法,请参阅 updateAsync。
根据 modifier
修改与 selector
匹配的文档(请参阅 修改器文档)。
update
的行为取决于它是受信任代码还是不受信任代码调用的。受信任代码包括服务器代码和方法代码。不受信任的代码包括客户端代码,例如事件处理程序和浏览器的 JavaScript 控制台。
受信任的代码可以通过将
multi
设置为 true 来一次修改多个文档,并且可以使用任意 Mongo 选择器 来查找要修改的文档。它绕过由allow
和deny
设置的任何访问控制规则。如果您不传递回调,则将从update
调用中返回受影响的文档数量。不受信任的代码一次只能修改一个文档,由其
_id
指定。只有在检查任何适用的allow
和deny
规则后,才允许进行修改。受影响的文档数量将返回到回调函数。不受信任的代码无法执行 upsert,除非在不安全模式下。
在服务器端,应使用 updateAsync
。
在客户端,update
永远不会阻塞。如果您不提供回调并且更新在服务器上失败,则 Meteor 将向控制台记录警告。如果您提供回调,如果出现错误,Meteor 将使用错误参数调用该函数,或者如果更新成功,则使用第二个参数指示受影响的文档数量。
// Give the 'Winner' badge to each user with a score greater than 10. If they
// are logged in and their badge list is visible on the screen, it will update
// automatically as they watch.
Meteor.methods({
async declareWinners() {
await Players.updateAsync(
{ score: { $gt: 10 } },
{
$addToSet: { badges: "Winner" },
},
{ multi: true }
);
},
});
// When the 'give points' button in the admin dashboard is pressed, give 5
// points to the current player. The new score will be immediately visible on
// everyone's screens.
Template.adminDashboard.events({
"click .give-points"() {
Players.update(Session.get("currentPlayer"), {
$inc: { score: 5 },
});
},
});
您可以通过将 upsert
选项设置为 true 来使用 update
执行 Mongo upsert。您还可以使用 upsert
方法执行 upsert,除了受影响的文档数量外,它还返回插入的文档的 _id
(如果有)。
Collection.updateAsync
摘要
修改集合中一个或多个文档。返回匹配文档的数量。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要修改哪些文档 | 是 |
modifier | MongoModifier | 指定如何修改文档 | 是 |
options | 对象 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Promise */
const result = Collection.updateAsync(
MongoSelector,
MongoModifier,
options, // this param is optional
);
update
的异步版本,返回一个 Promise
。
Collection.upsert
摘要
异步修改集合中一个或多个文档,或者如果未找到匹配的文档则插入一个文档。返回一个包含键 numberAffected
(修改的文档数量)和 insertedId
(插入的文档的唯一 _id,如果有)的对象。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要修改哪些文档 | 是 |
modifier | MongoModifier | 指定如何修改文档 | 是 |
options | 对象 | 否 | |
callback | 函数 | 可选。如果存在,则以错误对象作为第一个参数调用,如果无错误,则以受影响的文档数量作为第二个参数调用。 | 否 |
// Collection is an instance of Mongo.Collection
Collection.upsert(
MongoSelector,
MongoModifier,
options, // this param is optional
() => {}, // this param is optional
);
警告
仅限客户端。有关服务器/同构用法,请参阅 upsertAsync。
根据 modifier
修改与 selector
匹配的文档,或者如果没有修改任何文档,则插入一个文档。upsert
与使用 upsert
选项设置为 true 调用 update
相同,除了 upsert
的返回值是一个包含键 numberAffected
和 insertedId
的对象。(update
仅返回受影响的文档数量。)
Collection.upsertAsync
摘要
修改集合中一个或多个文档,或者如果未找到匹配的文档则插入一个文档。返回一个包含键 numberAffected
(修改的文档数量)和 insertedId
(插入的文档的唯一 _id,如果有)的对象。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要修改哪些文档 | 是 |
modifier | MongoModifier | 指定如何修改文档 | 是 |
options | 对象 | 否 |
// Collection is an instance of Mongo.Collection
/** @returns Promise */
const result = Collection.upsertAsync(
MongoSelector,
MongoModifier,
options, // this param is optional
);
upsert
的异步版本,返回一个 Promise
。
Collection.remove
摘要
从集合中删除文档
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要删除哪些文档 | 是 |
callback | 函数 | 可选。如果存在,则以错误对象作为第一个参数调用,如果无错误,则以受影响的文档数量作为第二个参数调用。 | 否 |
// Collection is an instance of Mongo.Collection
Collection.remove(
MongoSelector,
() => {}, // this param is optional
);
警告
仅限客户端。有关服务器/同构用法,请参阅 removeAsync。
查找与 selector
匹配的所有文档并将其从集合中删除。
remove
的行为取决于它是受信任代码还是不受信任代码调用的。受信任代码包括服务器代码和方法代码。不受信任的代码包括客户端代码,例如事件处理程序和浏览器的 JavaScript 控制台。
受信任的代码可以使用任意 Mongo 选择器 来查找要删除的文档,并且可以通过传递与多个文档匹配的选择器来一次删除多个文档。它绕过由
allow
和deny
设置的任何访问控制规则。如果您不传递回调,则将从remove
返回已删除文档的数量。作为安全措施,如果省略
selector
(或为undefined
),则不会删除任何文档。如果您确实要从集合中删除所有文档,请将selector
设置为{}
。不受信任的代码一次只能删除一个文档,由其
_id
指定。只有在检查任何适用的allow
和deny
规则后,才会删除该文档。已删除文档的数量将返回到回调函数。
在服务器端,应使用 removeAsync
。
在客户端,remove
永远不会阻塞。如果您没有提供回调函数,并且在服务器上删除操作失败,则 Meteor 会将警告信息记录到控制台。如果您提供了回调函数,如果发生错误,Meteor 会将错误参数传递给该函数;如果删除操作成功,则会将第二个参数传递给该函数,表示已删除的文档数量。
// When the server starts, clear the log and delete all players with a karma of
// less than -2.
Meteor.startup(async () => {
if (Meteor.isServer) {
await Logs.removeAsync({});
await Players.removeAsync({ karma: { $lt: -2 } });
}
});
// When the 'remove' button is clicked on a chat message, delete that message.
Template.chat.events({
"click .remove"() {
Messages.remove(this._id);
},
});
Collection.removeAsync
摘要
从集合中删除文档
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
selector | MongoSelector | 指定要删除哪些文档 | 是 |
// Collection is an instance of Mongo.Collection
/** @returns Promise */
const result = Collection.removeAsync(
MongoSelector
);
返回 Promise
的 remove
的异步版本。
Collection.createIndex仅限服务器端
仅限服务器端
摘要
异步地在集合上创建指定的索引。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
索引 | 对象 | 一个包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段的升序索引,指定值为 | 是 |
options | 对象 | 所有选项都列在 MongoDB 文档 中 | 否 |
// Collection is an instance of Mongo.Collection
Collection.createIndex(
index,
options, // this param is optional
);
为了实现高效和高性能的查询,您有时需要定义除默认的 _id
字段之外的其他索引。您应该为用于查找集合中文档的字段(或字段组合)添加索引。这就是 createIndex
发挥作用的地方。它接收两个对象。第一个是键和索引类型规范(哪个字段以及如何索引它们),第二个是选项,例如索引名称。有关索引工作原理的详细信息,请阅读 MongoDB 文档。
请注意,索引仅适用于服务器和 MongoDB 集合。目前,Minimongo 中未实现索引。
在 Meteor 中定义 Players 集合上的简单索引的示例
Players.createIndex({ userId: 1 }, { name: "user reference on players" });
有时,您或某个包可能会更改已建立的索引。这可能会引发错误并阻止启动。对于您可以重新构建索引或更改影响过多索引的情况,您可以在 settings.json
中将 reCreateIndexOnOptionMismatch
设置为 true
{
"packages": {
"mongo": {
"reCreateIndexOnOptionMismatch": true
}
}
}
仅当您处理跨多个索引的更改并且无法手动修复它们并且您可以承受重新构建索引时才应使用此选项,因为这将销毁旧索引并创建一个新索引。请谨慎使用此选项。
Collection.createIndexAsync仅限服务器端
仅限服务器端
摘要
异步地在集合上创建指定的索引。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
索引 | 对象 | 一个包含字段和值对的文档,其中字段是索引键,值描述该字段的索引类型。对于字段的升序索引,指定值为 | 是 |
options | 对象 | 所有选项都列在 MongoDB 文档 中 | 否 |
// Collection is an instance of Mongo.Collection
Collection.createIndexAsync(
index,
options, // this param is optional
);
返回 Promise
的 createIndex
的异步版本。
Collection.allow仅限服务器端
仅限服务器端
摘要
允许用户从客户端代码直接写入此集合,但须遵守您定义的限制。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
options | 对象 | 是 |
// Collection is an instance of Mongo.Collection
Collection.allow(
options
);
警告
虽然 allow
和 deny
使构建应用程序变得容易,但编写安全的 allow
和 deny
规则比看起来更难。我们建议开发人员避免使用 allow
和 deny
,并在准备好从其应用程序中删除 insecure
模式后直接切换到自定义方法。有关更多详细信息,请参阅 Meteor 安全指南。
当客户端在集合上调用 insert
/insertAsync
、update
/updateAsync
、remove
/removeAsync
时,集合的 allow
和 deny
回调将在服务器上调用以确定是否应允许写入。如果至少一个 allow
回调允许写入,并且没有 deny
回调拒绝写入,则允许写入继续进行。
仅当客户端尝试直接写入数据库时才会运行这些检查,例如通过从事件处理程序内部调用 update
/updateAsync
。服务器代码是受信任的,不受 allow
和 deny
限制。这包括使用 Meteor.call
调用的方法——预期它们会执行自己的访问检查,而不是依赖于 allow
和 deny
。
您可以根据需要多次调用 allow
,并且每次调用都可以包含 insert
/insertAsync
、update
/updateAsync
和 remove
/removeAsync
函数的任意组合。如果认为应允许操作,则这些函数应返回 true
。否则,它们应返回 false
或不返回任何内容(undefined
)。在这种情况下,Meteor 将继续搜索集合上的任何其他 allow
规则。
可用的回调函数为
回调函数
insert(userId, doc)
/insertAsync(userId, doc)
- 用户userId
想要将文档doc
插入到集合中。如果应允许此操作,则返回true
。如果客户端显式设置了
_id
字段,或者存在活动的transform
,则doc
将包含_id
字段。您可以使用它来防止用户指定任意_id
字段。update(userId, doc, fieldNames, modifier)
/updateAsync(userId, doc, fieldNames, modifier)
- 用户userId
想要更新数据库中的文档doc
。(doc
是来自数据库的文档的当前版本,不包含拟议的更新。)返回true
以允许更改。fieldNames
是客户端想要修改的doc
中(顶级)字段的数组,例如['name', 'score']
。modifier
是客户端想要执行的原始 Mongo 修改器;例如,{ $set: { 'name.first': 'Alice' }, $inc: { score: 1 } }
。仅支持 Mongo 修改器(例如
$set
和$push
的操作)。如果用户尝试替换整个文档而不是使用 $-修改器,则会在不检查allow
函数的情况下拒绝请求。remove(userId, doc)
/removeAsync(userId, doc)
- 用户userId
想要从数据库中删除doc
。返回true
以允许此操作。
当调用 update
/updateAsync
或 remove
/removeAsync
时,Meteor 默认情况下会从数据库中获取整个文档 doc
。如果您有大型文档,您可能希望仅获取函数实际使用的字段。通过将 fetch
设置为要检索的字段名称数组来实现此目的。
示例
// Create a collection where users can only modify documents that they own.
// Ownership is tracked by an `owner` field on each document. All documents must
// be owned by the user that created them and ownership can't be changed. Only a
// document's owner is allowed to delete it, and the `locked` attribute can be
// set on a document to prevent its accidental deletion.
const Posts = new Mongo.Collection("posts");
Posts.allow({
insert(userId, doc) {
// The user must be logged in and the document must be owned by the user.
return userId && doc.owner === userId;
},
update(userId, doc, fields, modifier) {
// Can only change your own documents.
return doc.owner === userId;
},
remove(userId, doc) {
// Can only remove your own documents.
return doc.owner === userId;
},
async insertAsync(userId, doc) {
// Any custom async validation is supported
const allowed = await allowInsertAsync(userId, doc);
return userId && allowed;
},
async updateAsync(userId, doc, fields, modifier) {
// Any custom async validation is supported
const allowed = await allowUpdateAsync(userId, doc);
return userId && allowed;
},
async removeAsync(userId, doc) {
// Any custom async validation is supported
const allowed = await allowRemoveAsync(userId, doc);
return userId && allowed;
},
fetch: ["owner"],
});
Posts.deny({
update(userId, doc, fields, modifier) {
// Can't change owners.
return _.contains(fields, "owner");
},
remove(userId, doc) {
// Can't remove locked documents.
return doc.locked;
},
async updateAsync(userId, doc, fields, modifier) {
// Any custom async validation is supported
const denied = await denyUpdateAsync(userId, doc);
return userId && denied;
},
async removeAsync(userId, doc) {
// Any custom async validation is supported
const denied = await denyRemoveAsync(userId, doc);
return userId && denied;
},
fetch: ["locked"], // No need to fetch `owner`
});
如果您从未在集合上设置任何 allow
规则,则所有客户端对集合的写入都将被拒绝,并且只能从服务器端代码写入集合。在这种情况下,您必须为客户端允许执行的每个可能的写入创建一个方法。然后,您将使用 Meteor.call
调用这些方法,而不是让客户端直接在集合上调用 insert
/insertAsync
、update
/updateAsync
和 remove
/removeAsync
。
Meteor 还有一种特殊的“不安全模式”,用于快速原型化新应用程序。在不安全模式下,如果您尚未在集合上设置任何 allow
或 deny
规则,则所有用户都对集合具有完全写入权限。这是不安全模式的唯一效果。如果您在集合上调用 allow
或 deny
,即使是 Posts.allow({})
,也会像往常一样检查该集合上的访问权限。**新的 Meteor 项目默认情况下以不安全模式启动。**要关闭它,只需在您的终端中运行
meteor remove insecure
Collection.deny仅限服务器端
仅限服务器端
摘要
覆盖 allow
规则。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
options | 对象 | 是 |
// Collection is an instance of Mongo.Collection
Collection.deny(
options
);
警告
虽然 allow
和 deny
使构建应用程序变得容易,但编写安全的 allow
和 deny
规则比看起来更难。我们建议开发人员避免使用 allow
和 deny
,并在准备好从其应用程序中删除 insecure
模式后直接切换到自定义方法。有关更多详细信息,请参阅 Meteor 安全指南。
它的工作原理与 allow
类似,但它允许您确保某些写入肯定被拒绝,即使存在 allow
规则指示应允许它们。
当客户端尝试写入集合时,Meteor 服务器首先检查集合的 deny
规则。如果它们都不返回 true,则检查集合的 allow
规则。仅当没有 deny
规则返回 true
且至少一个 allow
规则返回 true
时,Meteor 才允许写入。
Collection.rawCollection仅限服务器端
仅限服务器端
摘要
返回与 Mongo.Collection
包装的 npm mongodb
驱动程序模块 中此集合对应的 Collection
对象。
// Collection is an instance of Mongo.Collection
Collection.rawCollection();
您在生成的原始集合上调用的方法(如 update
或 insert
)会返回 promise,并且可以在 Fiber 外部使用。
Collection.rawDatabase仅限服务器端
仅限服务器端
摘要
返回与 Mongo.Collection
包装的 npm mongodb
驱动程序模块 中此集合的数据库连接对应的 Db
对象。
// Collection is an instance of Mongo.Collection
Collection.rawDatabase();
游标
要创建游标,请使用 find
。要访问游标中的文档,请使用 forEach
、map
、fetch
、forEachAsync
、mapAsync
、fetchAsync
或 ES2015 的 迭代协议。
Cursor.forEach
摘要
对每个匹配的文档依次且同步地调用 callback
一次。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
callback | IterationCallback | 要调用的函数。它将使用三个参数调用:文档、基于 0 的索引和游标本身。 | 是 |
thisArg | 任何 | 一个对象,它将是 | 否 |
// Cursor is an instance of Mongo.Cursor
Cursor.forEach(
IterationCallback,
any, // this param is optional
);
此接口与 Array.forEach 兼容。
当从反应式计算中调用时,forEach
会注册对匹配文档的依赖项。
示例
// Print the titles of the five top-scoring posts.
const topPosts = Posts.find({}, { sort: { score: -1 }, limit: 5 });
let count = 0;
topPosts.forEach((post) => {
console.log(`Title of post ${count}: ${post.title}`);
count += 1;
});
警告
仅限客户端。有关服务器/同构用法,请参阅 removeAsync。
Cursor.forEachAsync
摘要
对每个匹配的文档依次且同步地调用 callback
一次。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
callback | IterationCallback | 要调用的函数。它将使用三个参数调用:文档、基于 0 的索引和游标本身。 | 是 |
thisArg | 任何 | 一个对象,它将是 | 否 |
// Cursor is an instance of Mongo.Cursor
/** @returns Promise */
const result = Cursor.forEachAsync(
IterationCallback,
any, // this param is optional
);
返回 Promise
的 forEach
的异步版本。
与 forEach
中相同的示例,但使用 forEachAsync
// Print the titles of the five top-scoring posts.
const topPosts = Posts.find({}, { sort: { score: -1 }, limit: 5 });
let count = 0;
await topPosts.forEachAsync((post) => {
console.log(`Title of post ${count}: ${post.title}`);
count += 1;
});
console.log("All done!"); // This will be printed after all the posts are printed.
Cursor.map
摘要
将回调映射到所有匹配的文档上。返回一个数组。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
callback | IterationCallback | 要调用的函数。它将使用三个参数调用:文档、基于 0 的索引和游标本身。 | 是 |
thisArg | 任何 | 一个对象,它将是 | 否 |
// Cursor is an instance of Mongo.Cursor
Cursor.map(
IterationCallback,
any, // this param is optional
);
此接口与 Array.map 兼容。
当从反应式计算中调用时,map
会注册对匹配文档的依赖项。
在服务器上,如果 callback
产生,则在第一个调用等待时,可能会发生对 callback
的其他调用。如果需要严格的顺序执行,请改用 forEach
。
警告
仅限客户端使用。有关服务器/同构用法,请参阅 mapAsync。
Cursor.mapAsync
摘要
将回调映射到所有匹配的文档上。返回一个数组。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
callback | IterationCallback | 要调用的函数。它将使用三个参数调用:文档、基于 0 的索引和游标本身。 | 是 |
thisArg | 任何 | 一个对象,它将是 | 否 |
// Cursor is an instance of Mongo.Cursor
/** @returns Promise */
const result = Cursor.mapAsync(
IterationCallback,
any, // this param is optional
);
map
的异步版本,返回一个 Promise
。
Cursor.fetch
摘要
将所有匹配的文档作为数组返回。
// Cursor is an instance of Mongo.Cursor
/** @returns Array<Object> */
const result = Cursor.fetch();
当从响应式计算中调用时,fetch
会注册对匹配文档的依赖关系。
警告
仅限客户端使用。有关服务器/同构用法,请参阅 fetchAsync。
Cursor.fetchAsync
摘要
将所有匹配的文档作为数组返回。
// Cursor is an instance of Mongo.Cursor
/** @returns Promise */
const result = Cursor.fetchAsync();
fetch
的异步版本,返回一个 Promise
。
Cursor.count
摘要
返回与查询匹配的文档数量。此方法已自 MongoDB 4.0 起弃用;请参阅 Collection.countDocuments
和 Collection.estimatedDocumentCount
以获取替代方法。
// Cursor is an instance of Mongo.Cursor
/** @returns Number */
const result = Cursor.count();
与其他函数不同,count
仅注册对匹配文档数量的依赖关系。(仅更改或重新排序结果集中文档的更新不会触发重新计算。)
警告
仅限客户端使用。有关服务器/同构用法,请参阅 countAsync。
Cursor.countAsync
摘要
返回与查询匹配的文档数量。此方法已自 MongoDB 4.0 起弃用;请参阅 Collection.countDocuments
和 Collection.estimatedDocumentCount
以获取替代方法。
// Cursor is an instance of Mongo.Cursor
/** @returns Promise */
const result = Cursor.countAsync();
count
的异步版本,返回一个 Promise
。
Cursor.observeAsync
摘要
监视查询。在结果集更改时接收回调。
// Cursor is an instance of Mongo.Cursor
Cursor.observeAsync();
建立一个实时查询,当查询结果更改时调用回调。回调接收受影响文档的完整内容,以及适用的旧内容。如果您只需要接收更改的字段,请参阅 observeChangesAsync
。
callbacks
可以具有以下函数作为属性
回调
added(document)
或addedAt(document, atIndex, before)
新文档document
进入结果集。新文档出现在位置atIndex
。它紧接在_id
为before
的文档之前。如果新文档位于结果的末尾,则before
将为null
。changed(newDocument, oldDocument)
或changedAt(newDocument, oldDocument, atIndex)
文档的内容以前为oldDocument
,现在为newDocument
。已更改文档的位置为atIndex
。removed(oldDocument)
或removedAt(oldDocument, atIndex)
文档oldDocument
不再位于结果集中。它曾经位于位置atIndex
。movedTo(document, fromIndex, toIndex, before)
文档在结果集中更改了其位置,从fromIndex
到toIndex
(位于id
为before
的文档之前)。其当前内容为document
。
当您不关心结果集中文档的顺序时,请使用 added
、changed
和 removed
。它们比 addedAt
、changedAt
和 removedAt
更有效。
在 observeAsync
返回之前,将调用 added
(或 addedAt
)零次或多次以传递查询的初始结果。
observeAsync
返回实时查询句柄的 promise,该句柄是一个具有 stop
方法的对象。调用不带参数的 stop
以停止调用回调函数并拆除查询。在您调用此方法之前,查询将无限期运行。如果从 Tracker.autorun
计算中调用 observeAsync
,则在重新运行或停止计算时会自动停止它。
提示
建议使用 observeAsync
以保持客户端和服务器代码的同构性。
observe
保持同步,以便更轻松地管理客户端处理程序。
(如果使用选项 reactive
设置为 false 创建了游标,它将仅传递初始结果,并且不会调用任何进一步的回调;无需在句柄上调用 stop
。)
Cursor.observeChangesAsync
摘要
监视查询。在结果集更改时接收回调。仅将旧文档和新文档之间的差异传递给回调。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
回调 | 对象 | 用于在结果集更改时传递结果集的函数 | 是 |
// Cursor is an instance of Mongo.Cursor
Cursor.observeChangesAsync(
callbacks
);
建立一个实时查询,当查询结果更改时调用回调。与 observeAsync
相比,observeChangesAsync
仅提供旧结果集和新结果集之间的差异,而不是更改的文档的完整内容。
callbacks
可以具有以下函数作为属性
回调
added(id, fields)
或addedBefore(id, fields, before)
新文档进入结果集。它具有指定的id
和fields
。fields
包含文档的所有字段,但不包括_id
字段。新文档位于由before
标识的文档之前,或者如果before
为null
则位于末尾。changed(id, fields)
由id
标识的文档更改了其内容。fields
包含具有其新值的已更改字段。如果从文档中删除了字段,则它将出现在fields
中,其值为undefined
。removed(id)
由id
标识的文档不再位于结果集中。movedBefore(id, before)
由id
标识的文档更改了其在结果集中的位置,现在出现在由before
标识的文档之前。
如果您不使用 addedBefore
或 movedBefore
,则 observeChangesAsync
的效率要高得多。
在 observeChangesAsync
返回之前,将调用 added
(或 addedBefore
)零次或多次以传递查询的初始结果。
observeChangesAsync
返回实时查询句柄的 promise,该句柄是一个具有 stop
方法的对象。调用不带参数的 stop
以停止调用回调函数并拆除查询。在您调用此方法之前,查询将无限期运行。如果从 Tracker.autorun
计算中调用 observeChangesAsync
,则在重新运行或停止计算时会自动停止它。
提示
建议使用 observeChangesAsync
以保持客户端和服务器代码的同构性。
observeChanges
保持同步,以便更轻松地管理客户端处理程序。
(如果使用选项 reactive
设置为 false 创建了游标,它将仅传递初始结果,并且不会调用任何进一步的回调;无需在句柄上调用 stop
。)
与
observeAsync
不同,observeChangesAsync
不提供绝对位置信息(即,atIndex
位置而不是before
位置)。这是为了提高效率。
示例
// Keep track of how many administrators are online.
let count = 0;
const cursor = Users.find({ admin: true, onlineNow: true });
const handle = await cursor.observeChangesAsync({
added(id, user) {
count += 1;
console.log(`${user.name} brings the total to ${count} admins.`);
},
removed() {
count -= 1;
console.log(`Lost one. We're now down to ${count} admins.`);
},
});
// After five seconds, stop keeping the count.
setTimeout(() => handle.stop(), 5000);
Mongo.ObjectID
摘要
创建一个 MongoDB 样式的 ObjectID
。如果您未指定 hexString
,则 ObjectID
将随机生成(不使用 MongoDB 的 ID 构造规则)。
参数
源代码名称 | 类型 | 描述 | 必需 |
---|---|---|---|
hexString | 字符串 | 可选。要创建的 ObjectID 的 24 个字符十六进制内容 | 否 |
import { Mongo } from "meteor/mongo"";
const objectID = new Mongo.ObjectID(
"hexString"
);
Mongo.ObjectID
遵循与Node MongoDB 驱动程序 ObjectID
类相同的 API。请注意,您必须使用 equals
方法(或 EJSON.equals
)来比较它们;===
运算符将不起作用。如果您正在编写需要处理可能是字符串或 ObjectID
的 _id
字段的通用代码,请使用 EJSON.equals
而不是 ===
来比较它们。
由 Meteor 创建的
ObjectID
值对其getTimestamp
方法将没有有意义的答案,因为 Meteor 目前完全随机地构造它们。
选择器
最简单的选择器只是一个字符串或 Mongo.ObjectID
。这些选择器匹配其 _id
字段中具有该值的文档。
稍微复杂一点的选择器形式是一个对象,其中包含一组必须在文档中匹配的键
// Matches all documents where `deleted` is false.
{ deleted: false }
// Matches all documents where the `name` and `cognomen` are as given.
{ name: 'Rhialto', cognomen: 'the Marvelous' }
// Matches every document.
{}
但它们还可以包含更复杂的测试
// Matches documents where `age` is greater than 18.
{
age: {
$gt: 18;
}
}
// Matches documents where `tags` is an array containing 'popular'.
{
tags: "popular";
}
// Matches documents where `fruit` is one of three possibilities.
{
fruit: {
$in: ["peach", "plum", "pear"];
}
}
请参阅完整文档。
修改器
修改器是一个对象,描述了如何通过更改文档的一些字段来就地更新文档。一些例子
// Set the `admin` property on the document to true.
{ $set: { admin: true } }
// Add 2 to the `votes` property and add 'Traz' to the end of the `supporters`
// array.
{ $inc: { votes: 2 }, $push: { supporters: 'Traz' } }
但是,如果修改器不包含任何 $-运算符,则它将被解释为文字文档,并完全替换数据库中之前的内容。(已验证的更新 目前不支持文字文档修改器。)
// Find the document with ID '123' and completely replace it.
Users.update({ _id: "123" }, { name: "Alice", friends: ["Bob"] });
请参阅修改器的完整列表。
排序说明符
可以使用您选择的几种语法来指定排序
// All of these do the same thing (sort in ascending order by key `a`, breaking
// ties in descending order of key `b`).
[['a', 'asc'], ['b', 'desc']]
['a', ['b', 'desc']]
{ a: 1, b: -1 }
// Sorted by `createdAt` descending.
Users.find({}, { sort: { createdAt: -1 } });
// Sorted by `createdAt` descending and by `name` ascending.
Users.find({}, { sort: [['createdAt', 'desc'], ['name', 'asc']] });
最后一种形式仅在您的 JavaScript 实现保留对象中键的顺序时才有效。大多数情况下,大多数情况下都是如此,但由您确保。
对于本地集合,您可以传递一个比较器函数,该函数接收两个文档对象,如果第一个文档排在前面,则返回 -1,如果第二个文档排在前面,则返回 1,或者如果两个文档都不排在前面,则返回 0。这是对 MongoDB 的 Minimongo 扩展。
字段说明符
查询可以指定要包含或排除在结果对象中的特定字段集。
要从结果对象中排除特定字段,字段说明符是一个字典,其键是字段名称,其值是 0
。所有未指定的字段都包含在内。
Users.find({}, { fields: { password: 0, hash: 0 } });
要仅包含结果文档中的特定字段,请使用 1
作为值。_id
字段仍包含在结果中。
Users.find({}, { fields: { firstname: 1, lastname: 1 } });
除一个例外外,无法混合包含和排除样式:键必须全部为 1 或全部为 0。例外是您可以在包含说明符中指定 _id: 0
,这也会将 _id
从结果对象中排除。但是,此类字段说明符不能与 observeChangesAsync
、observeAsync
、从发布函数返回的游标一起使用。它们可以与 fetch
、findOne
、forEach
和 map
一起使用。
客户端尚不支持诸如 $
和 $elemMatch
之类的字段运算符。
一个更高级的例子
Users.insert({
alterEgos: [
{ name: "Kira", alliance: "murderer" },
{ name: "L", alliance: "police" },
],
name: "Yagami Light",
});
Users.findOne({}, { fields: { "alterEgos.name": 1, _id: 0 } });
// Returns { alterEgos: [{ name: 'Kira' }, { name: 'L' }] }
请参阅MongoDB 文档以了解嵌套字段规则和数组行为的详细信息。
连接到您的数据库
在开发应用程序时,Meteor 会启动一个本地 MongoDB 实例并自动连接到它。在生产环境中,您必须指定一个名为 MONGO_URL
的环境变量,指向您的数据库,并使用 标准的 MongoDB 连接字符串格式。
如果您想连接到不同的 MongoDB 实例,也可以在开发环境中设置
MONGO_URL
。
如果您想对实时查询使用 oplog 尾部跟踪,则还应设置 MONGO_OPLOG_URL
(通常您需要一个具有 oplog 访问权限的特殊用户,但具体细节可能因您托管 MongoDB 的方式而异。请阅读 此处了解更多信息)。
从 Meteor 1.4 开始,您必须确保在您的
METEOR_OPLOG_URL
上设置了replicaSet
参数。
MongoDB 连接选项
MongoDB 提供了许多连接选项,通常默认设置即可,但在某些情况下,您可能需要传递其他选项。您可以通过两种方式实现。
Meteor 设置
您可以使用您的 Meteor 设置文件在 packages
> mongo
中名为 options
的属性中设置选项,这些值将作为 MongoDB 连接方法的选项提供。
此选项在 Meteor 1.10.2 中引入。
例如,您可能希望为 TLS 连接指定证书(此处查看选项),然后您可以使用以下选项:
"packages": {
"mongo": {
"options": {
"tls": true,
"tlsCAFileAsset": "certificate.pem"
}
}
}
如果选项名称(键)以 Asset
结尾,Meteor 会将相对路径转换为绝对路径。为了使此功能正常工作,您需要将文件放在项目根目录下的 private
文件夹中。在示例中,Mongo 连接将接收以下内容:
"packages": {
"mongo": {
"options": {
"tls": true,
"tlsCAFile": "/absolute/path/certificate.pem"
}
}
}
请注意,最终的选项名称(键)末尾不包含 Asset
,这符合 MongoDB 的预期。
在某些 MongoDB 托管服务提供商中,此配置是必要的,以避免出现以下错误:MongoNetworkError: failed to connect to server [sg-meteorappdb-32194.servers.mongodirector.com:27017] on first connect [Error: self signed certificate
。
避免此错误的另一种方法是使用此选项允许无效证书:
"packages": {
"mongo": {
"options": {
"tlsAllowInvalidCertificates": true
}
}
}
您可以传递任何有效的 MongoDB 选项,这些只是使用证书配置的示例。
Mongo Oplog 选项
Oplog 选项在 Meteor 2.15.1 中引入。如果您设置了
MONGO_OPLOG_URL
环境变量,Meteor 将使用 MongoDB 的 Oplog 通过您的订阅向您的用户显示高效的实时更新。
由于 Meteor 的 Oplog 实现背后的构建方式,如果您在某些集合中预计会有大量写入操作,这可能会导致您的 Meteor 应用服务器出现较大的 CPU 尖峰,即使您在这些集合的任何数据/文档上都没有发布/订阅。有关此问题的更多信息,请查看 2016 年的这篇博文、2022 年的这个 GitHub 讨论 或 2023 年的这个 Meteor 论坛帖子。
为了解决这个问题,引入了2 个 Oplog 设置来调整哪些集合在 oplog 中被监视或忽略。
排除:例如,要排除名为 products
和 prices
的 2 个集合中所有文档的更新/插入,您需要在 Meteor 设置文件中设置以下设置:
"packages": {
"mongo": {
"oplogExcludeCollections": ["products", "prices"]
}
}
包含:反之,如果您只想监视/包含名为 chats
和 messages
的 2 个集合中文档的 oplog 更改,则可以使用以下设置:
"packages": {
"mongo": {
"oplogIncludeCollections": ["chats", "messages"]
}
}
出于显而易见的原因,同时使用 oplogExcludeCollections
和 oplogIncludeCollections
是不可能的,并且会导致错误。
Mongo.setConnectionOptions(options)
您还可以调用 Mongo.setConnectionOptions
来设置连接选项,但您需要在任何其他使用 Mongo 连接的包初始化之前调用它,因此您需要在包中添加此代码,并将其添加到其他包(如 accounts-base
)之上,在您的 .meteor/packages
文件中。
此选项在 Meteor 1.4 中引入。