Collections
Meteor用集合保存数据。集合里保存的Javascript对象叫做文档。使用new Mongo.Collection
声明一个集合。
new Mongo.Collection(name, [options])
Anywhere
Constructor for a Collection
Arguments
name String
The name of the collection. If null, creates an unmanaged (unsynchronized) local collection.
调用Mongo.Collection
构造函数创建一个集合对象,它的行为就像MongoDB 的集合。如果在创建集合时传入了一个name参数,那么声明的就是一个持久性集合 — 保存在服务端并可以发布到客户端。
要想使客户端代码和服务端代码都可以通过相同的API访问相同的集合,最好在一个客户端和服务端都能加载到的javascript文件中把集合声明为全局变量。
示例:声明两个命名的,持久性的集合作为全局变量:
// In a JS file that's loaded on the client and the server
Posts = new Mongo.Collection("posts");
Comments = new Mongo.Collection("comments");
如果传入null
作为name参数,那么创建出来的就是一个本地集合。本地集合不会在客户端和服务端之间进行同步;它只是javascript对象的临时集合,支持Mongo-style find
, insert
, update
, 和 remove
操作。
默认情况下,Meteor会自动发布所有集合里的文档到每一个连接上的客户端。要禁用此行为,必须移除autopublish
包:
$ meteor remove autopublish
然后,使用Meteor.publish
和 Meteor.subscribe
来指定集合的哪一部分发送到哪些客户端。
使用findOne
和 find
从集合里检索文档。
collection.findOne([selector], [options])
Anywhere
Finds the first document that matches the selector, as ordered by sort and skip options.
Arguments
selector Mongo Selector, Object ID, or String
A query describing the documents to find
Options
sort Mongo Sort Specifier
Sort order (default: natural order)
skip Number
Number of results to skip at the beginning
fields Mongo Field Specifier
Dictionary of fields to return or exclude.
findOne
方法可以从集合里查找特定的文档。调用findOne
时,通常都会传入一个特定文档的_id
:
var post = Posts.findOne(postId);
然而,也可以给findOne
传入一个Mongo 选择器,Mongo选择器是一个对象,指明了目标文档要满足的一系列属性。 例如,下面的选择器
var post = Posts.findOne({
createdBy: "12345",
title: {$regex: /first/}
});
会匹配到下面的文档
{
createdBy: "12345",
title: "My first post!",
content: "Today was a good day." }
关于MongoDB query operators 例如$regex
, $lt
(小于), $text
(文本搜索)的更多信息参见MongoDB documentation。
一个非常有用但是不那么明显的功能就是Mongo 选择器可以匹配数组里的元素。例如:下面的选择器
Post.findOne({
tags: "meteor" });
会匹配到下面的文档
{
title: "I love Meteor",
createdBy: "242135223",
tags: ["meteor", "javascript", "fun"] }
findOne
方法和Session.get
一样,也是响应式的,也就是说,如果你在template helper或是 Tracker.autorun
回调函数中使用了findOne
,如果findOne
返回的文档发生了变化,那么模板就会自动重新渲染,计算会重新执行。
注意,如果findOne
没有找到任何文档,则返回null
,通常发生在文档还没加载或是已经从集合中移除,所以要有处理null
值的准备。
collection.find([selector], [options])
Anywhere
Find the documents in a collection that match the selector.
Arguments
selector Mongo Selector, Object ID, or String
A query describing the documents to find
Options
sort Mongo Sort Specifier
Sort order (default: natural order)
skip Number
Number of results to skip at the beginning
limit Number
Maximum number of results to return
fields Mongo Field Specifier
Dictionary of fields to return or exclude.
find
方法和findOne
类似,不同的是,它不返回单一文档,而是返回一个MongoDB 游标。游标是一个特殊的对象,代表一个查询里会被返回的文档列表。可以在模板Helper里返回游标,或是其它可以返回数组的地方:
Template.blog.helpers({
posts: function () {
// this helper returns a cursor of
// all of the posts in the collection
return Posts.find();
}
});
<!-- a template that renders multiple posts -->
<template name="blog">
{{#each posts}}
<h1>{{title}}</h1>
<p>{{content}}</p>
{{/each}}
</template>
要想从一个游标里检索当前的文档列表时,调用游标的.fetch()
方法:
// get an array of posts
var postsArray = Posts.find().fetch();
记住,虽然调用fetch
的计算会在数据变化时重新运行,但是the resulting array will not be reactive if it is passed somewhere else.
通过调用insert
,update
, 或 remove
来修改保存在Mongo.Collection
里的数据。
collection.insert(doc, [callback])
Anywhere
Insert a document in the collection. Returns its unique _id.
Arguments
doc Object
The document to insert. May not yet have an _id attribute, in which case Meteor will generate one for you.
callback Function
Optional. If present, called with an error object as the first argument and, if no error, the _id as the second.
下面的例子展示了如何插入文档到集合里:
Posts.insert({
createdBy: Meteor.userId(),
createdAt: new Date(),
title: "My first post!",
content: "Today was a good day." });
每个Mongo.Collection
里的每个文档都有一个_id
字段。它必须是唯一的,如果你没有提供,会自动生成。collection.findOne
使用_id
可以用来检索特定的文档。
collection.update(selector, modifier, [options], [callback])
Anywhere
Modify one or more documents in the collection. Returns the number of affected documents.
Arguments
selector Mongo Selector, Object ID, or String
Specifies which documents to modify
modifier Mongo Modifier
Specifies how to modify the documents
callback Function
Optional. If present, called with an error object as the first argument and, if no error, the number of affected documents as the second.
Options
multi Boolean
True to modify all matching documents; false to only modify one of the matching documents (the default).
upsert Boolean
True to insert a document if no matching documents are found.
这里的选择器和你传给find
方法的是一致的,它可以匹配多个文档。修改器是一个对象,它指明了对匹配到的文档要做的修改。注意:除非你使用了$set
操作符,否则update
方法会直接用修改器替换整个匹配到的文档。
下面的例子展示了,设置所有标题包含"first"的文章的内容字段
Posts.update({
title: {$regex: /first/}
}, {
$set: {content: "Tomorrow will be a great day."}
});
关于支持的所有operators参见MongoDB documentation。
有一点需要注意:当在客户端调用update
的时候,只能通过_id
来查找文档。要使用所有可用的选择器,必须在服务端代码或是 method中调用update
。
collection.remove(selector, [callback])
Anywhere
Remove documents from the collection
Arguments
selector Mongo Selector, Object ID, or String
Specifies which documents to remove
callback Function
Optional. If present, called with an error object as its argument.
remove
方法使用和find
、update
一样的选择器,并且从数据库中移除所有匹配到的文档。请小心使用remove
— 删掉的数据没办法恢复。
和update
一样,客户端代码只能通过_id
移除文档,而服务端代码和methods可以使用任何选择器移除文档。
collection.allow(options)
Server
Allow users to write directly to this collection from client code, subject to limitations you define.
Options
insert, update, remove Function
Functions that look at a proposed modification to the database and return true if it should be allowed.
在新创建的APP中,Meteor允许任何客户端和服务端代码调用insert
, update
, 和 remove
。这是因为用meteor create
创建的APP默认包含了insecure
包,目的是简化开发。很显然,如果任何用户都可以修改数据库,这是很不安全的,所以移除insecure
包,并声明一些权限规则是很重要的:
$ meteor remove insecure
一旦你移除了insecure
包,就可以用allow
和deny
来控制谁可以执行哪些数据库操作。默认情况下,客户端所有的操作都被禁止,所以,需要添加一些allow
规则。记住:服务端代码和methods 不受allow
和deny
影响 — 这些规则只应用于当不可信的客户端代码调用insert
, update
, 和 remove
时。
例如,假设只有当createBy
字段为当前用户ID时,才允许用户插入新文章,这样用户就不能冒充其他人
// In a file loaded on the server (ignored on the client)
Posts.allow({
insert: function (userId, post) {
// can only create posts where you are the author
return post.createdBy === userId;
},
remove: function (userId, post) {
// can only delete your own posts
return post.createdBy === userId;
}
// since there is no update field, all updates
// are automatically denied
});
allow
方法接受三个回调函数:insert
,remove
,update
。三个回调函数的第一个参数是登录用户的_id
,其余的参数如下:
insert(userId, document)
document
是将要插入到数据库的文档。如果允许插入,则返回true
,否则返回false
update(userId, document, fieldNames, modifier)
document
是将要被修改的文档。fieldNames
是一个数组,包含了受这次修改影响的一级字段。modifier
是传给collection.update
的第二个参数Mongo Modifier。 如果使用这个回调无法实现正确的校验,那么推荐使用methods。 如果允许修改,则返回true
,否则返回false
remove(userId, document)
document
是将要从数据库中移除的文档。如果允许移除则返回true
,否则返回false
collection.deny(options)
Server
Override allow
rules.
Options
insert, update, remove Function
Functions that look at a proposed modification to the database and return true if it should be denied, even if an allow rule says otherwise.
deny
方法允许你选择性的重写allow
规则。只要有一个allow
回调函数返回true
,就允许修改,但必须所有deny
规则都返回false,才允许修改。
例如,我们要重写上面定义的allow
规则:排除特定标题的文章:
// In a file loaded on the server (ignored on the client)
Posts.deny({
insert: function (userId, post) {
// Don't allow posts with a certain title
return post.title === "First!";
}
});