Skip to content

Commit

Permalink
data section
Browse files Browse the repository at this point in the history
Conflicts:
	docs/client/concepts.html
  • Loading branch information
Matt DeBergalis committed Oct 16, 2012
1 parent 9cc1caa commit 55ed0c3
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 59 deletions.
162 changes: 105 additions & 57 deletions docs/client/concepts.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,72 +84,120 @@ <h2 id="structuringyourapp">Structuring your application</h2>
<template name="data">
{{#better_markdown}}

<h2 id="data">Data</h2>
<h2 id="data">Data and security</h2>

Meteor makes writing distributed client code as simple as talking to a
local database. It's a clean and simple approach, much easier than
building individual RPC endpoints, slow roundtrips to the server, and
orchestrating invalidation messages.

Every Meteor client includes an in-memory database cache. Each client's
cache holds valid copies of some set of documents that are stored in a
server's master database. When a matching document in that database
changes, Meteor automatically synchronizes that change to every
subscribed client.

To manage the client caches, your server code *publishes* sets of
documents, and your client code *subscribes* to those sets. For
example, if you are building a chat system, the server might publish two
sets: the set of all rooms, and the set of all messages in a given room.
Each client would subscribe to the master set of available rooms and the
set of messages in the currently-selected room. Once subscribed, the
client uses its cache as a fast local database, dramatically simplifying
your client model code.

Meteor's protocol for distributing document updates is database
agnostic. By default, Meteor applications use the
familiar [MongoDB API](http://www.mongodb.org/display/DOCS/Manual):
servers store documents in MongoDB collections, and clients cache those
documents in a client-side cache that implements the same Mongo API for
queries and updates.

// server: publish all room documents, and per-room messages
Meteor.publish("chatrooms");
local database. It's a clean, simple, and secure approach that obviates
the need to implement individual RPC endpoints, manually cache data on
the client to avoid slow roundtrips to the server, and carefully
orchestrate invalidation messages to every client as data changes.

In Meteor, the client and server share the same database API. The same
exact application code -- like validators and computed properties -- can
often run in both places. But while code running on the server has
direct access to the database, code running on the client does *not*.
This distinction is the basis for Meteor's data security model.

{{#note}}
By default, a new Meteor app includes the `autopublish` and `insecure`
packages, which together mimic the effect of each client having full
read/write access to the server's database. These are useful
prototyping tools, but typically not appropriate for production
applications. When you're ready, just remove the packages.
{{/note}}

Every Meteor client includes an in-memory database cache. To manage the
client cache, the server *publishes* sets of JSON documents, and the
client *subscribes* to those sets. As documents in a set change, the
server patches each client's cache.

Each document set is defined by a publish function on the server. The
publish function runs each time a new client subscribes to a document
set. The data in a document set can come from anywhere, but the common
case is to publish a database query.

// server: publish all room documents
Meteor.publish("all-rooms", function () {
return Rooms.find(); // everything
);

// server: publish all messages for a given room
Meteor.publish("messages", function (roomId) {
return Messages.find({room: roomId});
});

// client: subscribe to all rooms, and messages in the first room
Meteor.subscribe("chatrooms");
Meteor.subscribe("messages", Chatrooms.find()[0]._id);

Document modifications also propagate automatically. Modification
instructions like `insert`, `remove`, and `update` are executed
immediately on the client's cached data. *At the same time*, the
client sends that instruction up to the server, which executes the same
change against the master database. Usually the client and server
agree, but should they differ (permissions checking or overlapping with
another client, for example), the server's result will publish back down
to the client. And of course, all other clients with a matching
subscription automatically receive an updated document.

// create new message, executes on both client and server.
Messages.insert({room: 2413, text: "hello!"});

Putting it all together, these techniques accomplish *latency
compensation*. Clients hold a fresh copy of the data they need, and
never need to wait for a roundtrip to the server. And when clients
// server: publish the set of parties the logged-in user can see.
Meteor.publish("parties", function () {
return Parties.find({$or: [{"public": true},
{invited: this.userId},
{owner: this.userId}]});
});

Publish functions can provide different results to each client. In the
last example, a logged in user can only see `Party` documents that
are public, that the user owns, or that the user has been invited to.

Once subscribed, the client uses its cache as a fast local database,
dramatically simplifying client code. Reads never require a costly
round trip to the server. And they're limited to the contents of the
cache: a query for every document in a collection on a client will only
return documents the server is publishing to that client.

// client: start a parties subscription
Meteor.subscribe("parties");

// client: return array of Parties this client can read
return Parties.find().fetch(); // synchronous!

Sophisticated clients can turn subscriptions on and off to control how
much data is kept in the cache and manage network traffic. When a
subscription is turned off, all its documents are removed from the cache
unless the same document is also provided by another active
subscription.

When the client *changes* one or more documents, it sends a message to
the server requesting the change. The server checks the proposed change
against a set of allow/deny rules you write as JavaScript functions.
The server only accepts the change if all the rules pass.

// server: don't allow client to insert a party
Parties.allow({
insert: function (userId, party) {
return false;
}
});

// client: this will fail
var party = { ... };
Parties.insert(party);

If the server accepts the change, it applies the change to the database
and automatically propagates the change to other clients subscribed to
the affected documents. If not, the update fails, the server's database
remains untouched, and no other client sees the update.

Meteor has a cute trick, though. When a client issues a write to the
server, it also updates its local cache immediately, without waiting for
the server's response. This means the screen will redraw right away.
If the server accepted the update -- what ought to happen most of the
time in a properly behaving client -- then the client got a jump on the
change and didn't have to wait for the round trip to update its own
screen. If the server rejects the change, Meteor patches up the
client's cache with the server's result.

Putting it all together, these techniques accomplish latency
compensation. Clients hold a fresh copy of the data they need, and
never need to wait for a roundtrip to the server. And when clients
modify data, those modifications can run locally without waiting for the
confirmation from the server, while still giving the server final say
over the requested change.

You can substitute another database for MongoDB by providing a
server-side database driver and/or a client-side cache that implements
an alternative API. The `mongo-livedata` is a good starting point for
such a project.

XXX should we mention security/auth at all here, or just expect folks to keep
reading until the accounts section?
{{#note}}
The current release of Meteor supports MongoDB, the popular document
database, and the examples in this section use the
[MongoDB API](http://www.mongodb.org/display/DOCS/Manual). Future
releases will include support for other databases.
{{/note}}

{{/better_markdown}}
</template>
Expand Down Expand Up @@ -441,7 +489,7 @@ <h2 id="templates">Templates</h2>
<template name="packages_concept">
{{#better_markdown}}

<h2 id="smartpackages">Smart Packages</h2>
<h2 id="smartpackages">Smart packages</h2>

Meteor has an unusually powerful package system. All of the
functionality you've read about so far is implemented as standard
Expand Down
4 changes: 2 additions & 2 deletions docs/client/docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,11 @@ var toc = [
],
"Concepts", [
"Structuring your app",
"Data",
"Data and security",
"Reactivity",
"Live HTML",
"Templates",
"Smart Packages",
"Smart packages",
"Accounts",
"Deploying"
],
Expand Down

0 comments on commit 55ed0c3

Please sign in to comment.