Meteor API
Meteor global object has many functions and properties for handling utilities, network and much more.
Core APIs
Meteor.startup
Summary:
Run code when a client or a server starts.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | A function to run on startup. | Yes |
On a server, the function will run as soon as the server process is finished starting. On a client, the function will run as soon as the DOM is ready. Code wrapped in Meteor.startup
always runs after all app files have loaded, so you should put code here if you want to access shared variables from other files.
The startup
callbacks are called in the same order as the calls to Meteor.startup
were made.
On a client, startup
callbacks from packages will be called first, followed by <body>
templates from your .html
files, followed by your application code.
import { Meteor } from "meteor/meteor";
import { LinksCollection } from "/imports/api/links";
Meteor.startup(async () => {
// If the Links collection is empty, add some data.
if ((await LinksCollection.find().countAsync()) === 0) {
await LinksCollection.insertAsync({
title: "Do the Tutorial",
url: "https://www.meteor.com/tutorials/react/creating-an-app",
});
}
});
import React from "react";
import { createRoot } from "react-dom/client";
import { Meteor } from "meteor/meteor";
import { App } from "/imports/ui/App";
// Setup react root
Meteor.startup(() => {
const container = document.getElementById("react-target");
const root = createRoot(container);
root.render(<App />);
});
Meteor.promisify
Summary:
Takes a function that has a callback argument as the last one and promissify it. One option would be to use node utils.promisify, but it won't work on the browser.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
fn | function | ---- | Yes |
context | Object | ---- | No |
errorFirst | Boolean | If the callback follows the errorFirst style, default to true | No |
import { Meteor } from "meteor/meteor";
/** @returns function */
const result = Meteor.promisify(
() => {},
context, // this param is optional
false, // this param is optional
);
Meteor.defer
Summary:
Defer execution of a function to run asynchronously in the background (similar to Meteor.setTimeout(func, 0)
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The function to run | Yes |
import { Meteor } from "meteor/meteor";
Meteor.defer(
() => {}
);
Meteor.absoluteUrl
Summary:
Generate an absolute URL pointing to the application. The server reads from the ROOT_URL
environment variable to determine where it is running. This is taken care of automatically for apps deployed to Galaxy, but must be provided when using meteor build
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
path | String | A path to append to the root URL. Do not include a leading " | No |
options | Object | No |
import { Meteor } from "meteor/meteor";
Meteor.absoluteUrl(
"path", // this param is optional
options, // this param is optional
);
Meteor.settings
Summary:
Meteor.settings
contains deployment-specific configuration options. You can initialize settings by passing the --settings
option (which takes the name of a file containing JSON data) to meteor run
or meteor deploy
. When running your server directly (e.g. from a bundle), you instead specify settings by putting the JSON directly into the METEOR_SETTINGS
environment variable. If the settings object contains a key named public
, then Meteor.settings.public
will be available on the client as well as the server. All other properties of Meteor.settings
are only defined on the server. You can rely on Meteor.settings
and Meteor.settings.public
being defined objects (not undefined) on both client and server even if there are no settings specified. Changes to Meteor.settings.public
at runtime will be picked up by new client connections.
Meteor.release
Summary:
Meteor.release
is a string containing the name of the release with which the project was built (for example, "1.2.3"
). It is undefined
if the project was built using a git checkout of Meteor.
Meteor.isClient
Summary:
Boolean variable. True if running in client environment.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isClient) {
// do something
}
Meteor.isServer
Summary:
Boolean variable. True if running in server environment.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isServer) {
// do something
}
DANGER
Meteor.isServer
can be used to limit where code runs, but it does not prevent code from being sent to the client. Any sensitive code that you don’t want served to the client, such as code containing passwords or authentication mechanisms, should be kept in the server
directory.
Meteor.isCordova
Summary:
Boolean variable. True if running in a Cordova mobile environment.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isCordova) {
// do something
}
Meteor.isDevelopment
Summary:
Boolean variable. True if running in development environment.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isDevelopment) {
// do something
}
Meteor.isProduction
Summary:
Boolean variable. True if running in production environment.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isProduction) {
// do something
}
Meteor.isModern
Summary:
Boolean variable. True if running in a "modern" JS
environment, as determined by the modern
package.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isModern) {
// do something
}
Meteor.isTest
Summary:
Boolean variable. True when running unit tests (false if running tests in full app mode).
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isTest) {
// do something
}
Meteor.isAppTest
Summary:
Boolean variable. True if running tests against your application i.e meteor test --full-app
.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isAppTest) {
// do something
}
Meteor.isPackageTest
Summary:
Boolean variable. True if running tests against a Meteor package.
import { Meteor } from 'meteor/meteor';
/** @type {Boolean} */
if (Meteor.isPackageTest) {
// do something
}
Meteor.gitCommitHash
Summary:
Hexadecimal Git commit hash, if the application is using Git for version control. Undefined otherwise.
Method APIs
Meteor Methods are Remote Procedure Calls (RPCs) are functions defined by Meteor.methods
and called by Meteor.call
.
Meteor.methods
Summary:
Defines functions that can be invoked over the network by clients.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
methods | Object | Dictionary whose keys are method names and values are functions. | Yes |
The most basic way to define a method is to provide a function:
import { Meteor } from "meteor/meteor";
Meteor.methods({
sum(a, b) {
return a + b;
},
});
import { Meteor } from "meteor/meteor";
const result = await Meteor.callAsync("sum", 1, 2);
console.log(result); // 3
You can use Meteor.methods
to define multiple methods at once.
You can think of Meteor.methods
as a way of defining a remote object that is your server API.
A more complete example:
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { LinksCollection } from "/imports/api/links";
Meteor.methods({
async addLink(link) {
check(link, String); // check if the link is a string
// Do stuff...
const linkID = await LinksCollection.insertAsync(link);
if (/* you want to throw an error */) {
throw new Meteor.Error('Something is wrong', "Some details");
}
return linkID;
},
bar() {
// Do other stuff...
return 'baz';
}
});
import React from "react";
import { Meteor } from "meteor/meteor";
function Component() {
const addLink = () =>
Meteor.callAsync(
"addLink",
"https://www.meteor.com/tutorials/react/creating-an-app"
);
return (
<div>
<button onClick={addLink}>Add Link</button>
</div>
);
}
Calling methods
on the server defines functions that can be called remotely by clients. They should return an EJSON-able value or throw an exception. Inside your method invocation, this
is bound to a method invocation object, which provides the following:
isSimulation
: a boolean value, true if this invocation is a stub.unblock
: when called, allows the next method from this client to begin running.userId
: the id of the current user.setUserId
: a function that associates the current client with a user.connection
: on the server, the connection this method call was received on.
Calling methods
on the client defines stub functions associated with server methods of the same name. You don't have to define a stub for your method if you don't want to. In that case, method calls are just like remote procedure calls in other systems, and you'll have to wait for the results from the server.
If you do define a stub, when a client invokes a server method it will also run its stub in parallel. On the client, the return value of a stub is ignored. Stubs are run for their side-effects: they are intended to simulate the result of what the server's method will do, but without waiting for the round trip delay. If a stub throws an exception it will be logged to the console.
You use methods all the time, because the database mutators (insert
, update
, remove
) are implemented as methods. When you call any of these functions on the client, you're invoking their stub version that update the local cache, and sending the same write request to the server. When the server responds, the client updates the local cache with the writes that actually occurred on the server.
You don't have to put all your method definitions into a single Meteor.methods
call; you may call it multiple times, as long as each method has a unique name.
If a client calls a method and is disconnected before it receives a response, it will re-call the method when it reconnects. This means that a client may call a method multiple times when it only means to call it once. If this behavior is problematic for your method, consider attaching a unique ID to each method call on the client, and checking on the server whether a call with this ID has already been made. Alternatively, you can use Meteor.apply
with the noRetry option set to true.
Read more about methods and how to use them in the Methods article in the Meteor Guide.
This method can be used to determine if the current method invocation is asynchronous. It returns true if the method is running on the server and came from an async call(Meteor.callAsync
)
import { Meteor } from "meteor/meteor";
Meteor.methods({
async foo() {
return Meteor.isAsyncCall();
},
});
import { Meteor } from "meteor/meteor";
const result = await Meteor.callAsync("foo");
console.log(result); // true
Meteor.call("foo", (err, result) => {
console.log(result); // false
});
this.userId
The user id is an arbitrary string — typically the id of the user record in the database. You can set it with the setUserId
function. If you're using the Meteor accounts system then this is handled for you.
import { Meteor } from "meteor/meteor";
Meteor.methods({
foo() {
console.log(this.userId);
},
});
this.setUserId
Call this function to change the currently logged-in user on the connection that made this method call. This simply sets the value of userId
for future method calls received on this connection. Pass null
to log out the connection.
If you are using the built-in Meteor accounts system then this should correspond to the _id
field of a document in the Meteor.users
collection.
setUserId
is not retroactive. It affects the current method call and any future method calls on the connection. Any previous method calls on this connection will still see the value of userId
that was in effect when they started.
If you also want to change the logged-in user on the client, then after calling setUserId
on the server, call Meteor.connection.setUserId(userId)
on the client.
import { Meteor } from "meteor/meteor";
Meteor.methods({
foo() {
this.setUserId("some-id");
},
});
this.connection
Access inside a method invocation. The connection that this method was received on. null if the method is not associated with a connection, eg. a server initiated method call. Calls to methods made from a server method which was in turn initiated from the client share the same connection.
Meteor.Error
Summary:
This class represents a symbolic error thrown by a method.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
error | String | A string code uniquely identifying this kind of error. This string should be used by callers of the method to determine the appropriate action to take, instead of attempting to parse the reason or details fields. For legacy reasons, some built-in Meteor functions such as | Yes |
reason | String | Optional. A short human-readable summary of the error, like 'Not Found'. | No |
details | String | Optional. Additional information about the error, like a textual stack trace. | No |
import { Meteor } from "meteor/meteor"";
const error = new Meteor.Error(
"error",
"reason", // this param is optional
"details", // this param is optional
);
For example:
import { Meteor } from "meteor/meteor";
// on the server, pick a code unique to this error
// the reason field should be a useful debug message
Meteor.methods({
methodName() {
throw new Meteor.Error(
"logged-out",
"The user must be logged in to post a comment."
);
},
});
import { Meteor } from "meteor/meteor";
// on the client
Meteor.call("methodName", function (error) {
// identify the error
if (error && error.error === "logged-out") {
// show a nice error message
Session.set("errorMessage", "Please log in to post a comment.");
}
});
If you want to return an error from a method, throw an exception. Methods can throw any kind of exception. But Meteor.Error
is the only kind of error that a server will send to the client. If a method function throws a different exception, then it will be mapped to a sanitized version on the wire. Specifically, if the sanitizedError
field on the thrown error is set to a Meteor.Error
, then that error will be sent to the client. Otherwise, if no sanitized version is available, the client gets Meteor.Error(500, 'Internal server error')
.
Meteor.call
Summary:
Invokes a method with a sync stub, passing any number of arguments.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | Name of method to invoke | Yes |
arg1, arg2... | EJSONable | Optional method arguments | No |
asyncCallback | function | Optional callback, which is called asynchronously with the error or result after the method is complete. If not provided, the method runs synchronously if possible (see below). | No |
This is how to invoke a method with a sync stub. It will run the method on the server. If a stub is available, it will also run the stub on the client. (See also Meteor.apply
, which is identical to Meteor.call
except that you specify the parameters as an array instead of as separate arguments and you can specify a few options controlling how the method is executed.)
If you include a callback function as the last argument (which can't be an argument to the method, since functions aren't serializable), the method will run asynchronously: it will return nothing in particular and will not throw an exception. When the method is complete (which may or may not happen before Meteor.call
returns), the callback will be called with two arguments: error
and result
. If an error was thrown, then error
will be the exception object. Otherwise, error
will be undefined
and the return value (possibly undefined
) will be in result
.
// Asynchronous call
Meteor.call('foo', 1, 2, (error, result) => { ... });
If you do not pass a callback on the server, the method invocation will block until the method is complete. It will eventually return the return value of the method, or it will throw an exception if the method threw an exception. (Possibly mapped to 500 Server Error if the exception happened remotely and it was not a Meteor.Error
exception.)
// Synchronous call
const result = Meteor.call("foo", 1, 2);
On the client, if you do not pass a callback and you are not inside a stub, call
will return undefined
, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.
Finally, if you are inside a stub on the client and call another method, the other method is not executed (no RPC is generated, nothing "real" happens). If that other method has a stub, that stub stands in for the method and is executed. The method call's return value is the return value of the stub function. The client has no problem executing a stub synchronously, and that is why it's okay for the client to use the synchronous Meteor.call
form from inside a method body, as described earlier.
Meteor tracks the database writes performed by methods, both on the client and the server, and does not invoke asyncCallback
until all of the server's writes replace the stub's writes in the local cache. In some cases, there can be a lag between the method's return value being available and the writes being visible: for example, if another method still outstanding wrote to the same document, the local cache may not be up to date until the other method finishes as well. If you want to process the method's result as soon as it arrives from the server, even if the method's writes are not available yet, you can specify an onResultReceived
callback to Meteor.apply
.
WARNING
Use Meteor.call
only to call methods that do not have a stub, or have a sync stub. If you want to call methods with an async stub, Meteor.callAsync
can be used with any method.
Meteor.callAsync
Summary:
Invokes a method with an async stub, passing any number of arguments.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | Name of method to invoke | Yes |
arg1, arg2... | EJSONable | Optional method arguments | No |
import { Meteor } from "meteor/meteor";
/** @returns Promise */
const result = Meteor.callAsync(
"name",
{ num: 42 , someProp: "foo" }, // this param is optional
);
Meteor.callAsync
is just like Meteor.call
, except that it'll return a promise that you need to solve to get the result.
Meteor.apply
Summary:
Invoke a method passing an array of arguments.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | Name of method to invoke | Yes |
args | Array.<EJSONable> | Method arguments | Yes |
options | Object | No | |
asyncCallback | function | Optional callback; same semantics as in | No |
import { Meteor } from "meteor/meteor";
Meteor.apply(
"name",
[{ num: 42 , someProp: "foo" }],
options, // this param is optional
() => {}, // this param is optional
);
Meteor.apply
is just like Meteor.call
, except that the method arguments are passed as an array rather than directly as arguments, and you can specify options about how the client executes the method.
WARNING
Use Meteor.apply
only to call methods that do not have a stub, or have a sync stub. If you want to call methods with an async stub, Meteor.applyAsync
can be used with any method.
Meteor.applyAsync
Summary:
Invoke a method passing an array of arguments.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | Name of method to invoke | Yes |
args | Array.<EJSONable> | Method arguments | Yes |
options | Object | No |
import { Meteor } from "meteor/meteor";
Meteor.applyAsync(
"name",
[{ num: 42 , someProp: "foo" }],
options, // this param is optional
);
Meteor.applyAsync
is just like Meteor.apply
, except it is an async function, and it will consider that the stub is async.
Publish and subscribe
These functions control how Meteor servers publish sets of records and how clients can subscribe to those sets.
Meteor.publish Server only
Server only
Summary:
Publish a record set.
Publish functions can return a Collection.Cursor
, in which case Meteor will publish that cursor's documents to each subscribed client. You can also return an array of Collection.Cursor
s, in which case Meteor will publish all of the cursors.
WARNING
If you return multiple cursors in an array, they currently must all be from different collections. We hope to lift this restriction in a future release.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String or Object | If String, name of the record set. If Object, publications Dictionary of publish functions by name. If | Yes |
func | function | Function called on the server each time a client subscribes. Inside the function, | Yes |
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { Rooms } from "/imports/api/Rooms";
import { Messages } from "/imports/api/Messages";
// Server: Publish the `Rooms` collection, minus secret info...
Meteor.publish("rooms", function () {
return Rooms.find(
{},
{
fields: { secretInfo: 0 },
}
);
});
// ...and publish secret info for rooms where the logged-in user is an admin. If
// the client subscribes to both publications, the records are merged together
// into the same documents in the `Rooms` collection. Note that currently object
// values are not recursively merged, so the fields that differ must be top
// level fields.
Meteor.publish("adminSecretInfo", function () {
return Rooms.find(
{ admin: this.userId },
{
fields: { secretInfo: 1 },
}
);
});
// Publish dependent documents and simulate joins.
Meteor.publish("roomAndMessages", function (roomId) {
check(roomId, String);
return [
Rooms.find(
{ _id: roomId },
{
fields: { secretInfo: 0 },
}
),
Messages.find({ roomId }),
];
});
Alternatively, a publish function can directly control its published record set by calling the functions added
(to add a new document to the published record set), changed
(to change or clear some fields on a document already in the published record set), and removed
(to remove documents from the published record set). These methods are provided by this
in your publish function.
If a publish function does not return a cursor or array of cursors, it is assumed to be using the low-level added
/changed
/removed
interface, and it must also call ready
once the initial record set is complete.
import { Mongo } from "meteor/mongo";
export const Rooms = new Mongo.Collection("rooms");
export const SecretData = new Mongo.Collection("messages");
import { Meteor } from "meteor/meteor";
import { check } from "meteor/check";
import { Rooms, SecretData } from "/imports/api/collections";
// Publish the current size of a collection.
Meteor.publish("countsByRoom", function (roomId) {
check(roomId, String);
let count = 0;
let initializing = true;
// `observeChanges` only returns after the initial `added` callbacks have run.
// Until then, we don't want to send a lot of `changed` messages—hence
// tracking the `initializing` state.
const handle = Messages.find({ roomId }).observeChanges({
added: (id) => {
count += 1;
if (!initializing) {
this.changed("counts", roomId, { count });
}
},
removed: (id) => {
count -= 1;
this.changed("counts", roomId, { count });
},
// We don't care about `changed` events.
});
// Instead, we'll send one `added` message right after `observeChanges` has
// returned, and mark the subscription as ready.
initializing = false;
this.added("counts", roomId, { count });
this.ready();
// Stop observing the cursor when the client unsubscribes. Stopping a
// subscription automatically takes care of sending the client any `removed`
// messages.
this.onStop(() => handle.stop());
});
// Sometimes publish a query, sometimes publish nothing.
Meteor.publish("secretData", function () {
if (this.userId === "superuser") {
return SecretData.find();
} else {
// Declare that no data is being published. If you leave this line out,
// Meteor will never consider the subscription ready because it thinks
// you're using the `added/changed/removed` interface where you have to
// explicitly call `this.ready`.
return [];
}
});
import { Meteor } from "meteor/meteor";
import { Mongo } from "meteor/mongo";
import { Session } from "meteor/session";
// Declare a collection to hold the count object.
const Counts = new Mongo.Collection("counts");
// Subscribe to the count for the current room.
Tracker.autorun(() => {
Meteor.subscribe("countsByRoom", Session.get("roomId"));
});
// Use the new collection.
const roomCount = Counts.findOne(Session.get("roomId")).count;
console.log(`Current room has ${roomCount} messages.`);
WARNING
Meteor will emit a warning message if you call Meteor.publish
in a project that includes the autopublish
package. Your publish function will still work.
Read more about publications and how to use them in the Data Loading article in the Meteor Guide.
this.userId Server only
Server only
Summary:
Access inside the publish function. The id of the logged-in user, or null
if no user is logged in.
This is constant. However, if the logged-in user changes, the publish function is rerun with the new value, assuming it didn't throw an error at the previous run.
this.added Server only
Server only
Summary:
Call inside the publish function. Informs the subscriber that a document has been added to the record set.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
collection | String | The name of the collection that contains the new document. | Yes |
id | String | The new document's ID. | Yes |
fields | Object | The fields in the new document. If | Yes |
// this is an instance of Subscription
this.added(
"collection",
"id",
fields,
);
this.changed Server only
Server only
Summary:
Call inside the publish function. Informs the subscriber that a document in the record set has been modified.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
collection | String | The name of the collection that contains the changed document. | Yes |
id | String | The changed document's ID. | Yes |
fields | Object | The fields in the document that have changed, together with their new values. If a field is not present in | Yes |
// this is an instance of Subscription
this.changed(
"collection",
"id",
fields,
);
this.removed Server only
Server only
Summary:
Call inside the publish function. Informs the subscriber that a document has been removed from the record set.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
collection | String | The name of the collection that the document has been removed from. | Yes |
id | String | The ID of the document that has been removed. | Yes |
// this is an instance of Subscription
this.removed(
"collection",
"id",
);
this.ready Server only
Server only
Summary:
Call inside the publish function. Informs the subscriber that an initial, complete snapshot of the record set has been sent. This will trigger a call on the client to the onReady
callback passed to Meteor.subscribe
, if any.
// this is an instance of Subscription
this.ready();
this.onStop Server only
Server only
Summary:
Call inside the publish function. Registers a callback function to run when the subscription is stopped.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The callback function | Yes |
// this is an instance of Subscription
this.onStop(
() => {}
);
If you call observe
or observeChanges
in your publish handler, this is the place to stop the observes.
this.error Server only
Server only
Summary:
Call inside the publish function. Stops this client's subscription, triggering a call on the client to the onStop
callback passed to Meteor.subscribe
, if any. If error
is not a Meteor.Error
, it will be sanitized.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
error | Error | The error to pass to the client. | Yes |
// this is an instance of Subscription
this.error(
Error(error)
);
this.stop Server only
Server only
Summary:
Call inside the publish function. Stops this client's subscription and invokes the client's onStop
callback with no error.
// this is an instance of Subscription
this.stop();
this.connection Server only
Server only
Summary:
Access inside the publish function. The incoming connection for this subscription.
Meteor.subscribe Client only
Client only
Summary:
Subscribe to a record set. Returns a handle that provides
stop()
and ready()
methods.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
name | String | Name of the subscription. Matches the name of the
server's | Yes |
arg1, arg2... | EJSONable | Optional arguments passed to publisher function on server. | No |
callbacks | function or Object | Optional. May include | No |
When you subscribe to a record set, it tells the server to send records to the client. The client stores these records in local Minimongo collections, with the same name as the collection
argument used in the publish handler's added
, changed
, and removed
callbacks. Meteor will queue incoming records until you declare the Mongo.Collection
on the client with the matching collection name.
// It's okay to subscribe (and possibly receive data) before declaring the
// client collection that will hold it. Assume 'allPlayers' publishes data from
// the server's 'players' collection.
Meteor.subscribe("allPlayers");
// The client queues incoming 'players' records until the collection is created:
const Players = new Mongo.Collection("players");
The client will see a document if the document is currently in the published record set of any of its subscriptions. If multiple publications publish a document with the same _id
for the same collection the documents are merged for the client. If the values of any of the top level fields conflict, the resulting value will be one of the published values, chosen arbitrarily.
WARNING
Currently, when multiple subscriptions publish the same document only the top level fields are compared during the merge. This means that if the documents include different sub-fields of the same top level field, not all of them will be available on the client. We hope to lift this restriction in a future release.
The onReady
callback is called with no arguments when the server marks the subscription as ready. The onStop
callback is called with a Meteor.Error
if the subscription fails or is terminated by the server. If the subscription is stopped by calling stop
on the subscription handle or inside the publication, onStop
is called with no arguments.
Meteor.subscribe
returns a subscription handle, which is an object with the following properties:
import { Meteor } from "meteor/meteor";
const handle = Meteor.subscribe("allPlayers");
handle.ready(); // True when the server has marked the subscription as ready
handle.stop(); // Stop this subscription and unsubscribe from the server
handle.subscriptionId; // The id of the subscription this handle is for.
When you run Meteor.subscribe inside of Tracker.autorun, the handles you get will always have the same subscriptionId field. You can use this to deduplicate subscription handles if you are storing them in some data structure.
If you call Meteor.subscribe
within a reactive computation, for example using Tracker.autorun
, the subscription will automatically be cancelled when the computation is invalidated or stopped; it is not necessary to call stop
on subscriptions made from inside autorun
. However, if the next iteration of your run function subscribes to the same record set (same name and parameters), Meteor is smart enough to skip a wasteful unsubscribe/resubscribe. For example:
Tracker.autorun(() => {
Meteor.subscribe("chat", { room: Session.get("currentRoom") });
Meteor.subscribe("privateMessages");
});
This subscribes you to the chat messages in the current room and to your private messages. When you change rooms by calling Session.set('currentRoom', 'newRoom')
, Meteor will subscribe to the new room's chat messages, unsubscribe from the original room's chat messages, and continue to stay subscribed to your private messages.
Publication strategies
The following features are available from Meteor 2.4 or
ddp-server@2.5.0
Once you start scaling your application you might want to have more control on how the data from publications is being handled on the client. There are three publications strategies:
SERVER_MERGE
SERVER_MERGE
is the default strategy. When using this strategy, the server maintains a copy of all data a connection is subscribed to. This allows us to only send deltas over multiple publications.
NO_MERGE_NO_HISTORY
The NO_MERGE_NO_HISTORY
strategy results in the server sending all publication data directly to the client. It does not remember what it has previously sent to client and will not trigger removed messages when a subscription is stopped. This should only be chosen for special use cases like send-and-forget queues.
NO_MERGE
NO_MERGE
is similar to NO_MERGE_NO_HISTORY
but the server will remember the IDs it has sent to the client so it can remove them when a subscription is stopped. This strategy can be used when a collection is only used in a single publication.
When NO_MERGE
is selected the client will be handling gracefully duplicate events without throwing an exception. Specifically:
- When we receive an added message for a document that is already present in the client's collection, it will be changed.
- When we receive a change message for a document that is not in the client's collection, it will be added.
- When we receive a removed message for a document that is not in the client's collection, nothing will happen.
You can import the publication strategies from DDPServer
.
import { DDPServer } from "meteor/ddp-server";
const { SERVER_MERGE, NO_MERGE_NO_HISTORY, NO_MERGE } =
DDPServer.publicationStrategies;
You can use the following methods to set or get the publication strategy for publications:
setPublicationStrategy Server only
Server only
Summary:
Set publication strategy for the given collection. Publications strategies are available from DDPServer.publicationStrategies
. You call this method from Meteor.server
, like Meteor.server.setPublicationStrategy()
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
collectionName | String | ---- | Yes |
strategy | Object | ---- | Yes |
For the foo
collection, you can set the NO_MERGE
strategy as shown:
import { DDPServer } from "meteor/ddp-server";
Meteor.server.setPublicationStrategy(
"foo",
DDPServer.publicationStrategies.NO_MERGE
);
getPublicationStrategy Server only
Server only
Summary:
Gets the publication strategy for the requested collection. You call this method from Meteor.server
, like Meteor.server.getPublicationStrategy()
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
collectionName | String | ---- | Yes |
import { Meteor } from "meteor/meteor";
/** @returns Object */
const result = Meteor.server.getPublicationStrategy(
"collectionName"
);
Server connections
Functions to manage and inspect the network connection between the Meteor client and server.
import { Meteor } from "meteor/meteor";
const status = Meteor.status();
console.log(status);
// ^^^^
// {
// connected: Boolean,
// status: String,
// retryCount: Number,
// retryTime: Number,
// reason: String,
// }
Status object has the following fields:
connected
- Boolean : True if currently connected to the server. If false, changes and method invocations will be queued up until the connection is reestablished.status
- String: Describes the current reconnection status. The possible values areconnected
(the connection is up and running),connecting
(disconnected and trying to open a new connection),failed
(permanently failed to connect; e.g., the client and server support different versions of DDP),waiting
(failed to connect and waiting to try to reconnect) andoffline
(user has disconnected the connection).retryCount
- Number: The number of times the client has tried to reconnect since the connection was lost. 0 when connected.retryTime
- Number or undefined: The estimated time of the next reconnection attempt. To turn this into an interval until the next reconnection, This key will be set only whenstatus
iswaiting
. You canuse this snippet:jsretryTime - new Date().getTime();
reason
- String or undefined: Ifstatus
isfailed
, a description of why the connection failed.
Meteor.reconnect Client only
Client only
Summary:
Force an immediate reconnection attempt if the client is not connected to the server.
This method does nothing if the client is already connected.
import { Meteor } from "meteor/meteor";
Meteor.reconnect();
Meteor.disconnect Client only
Client only
Summary:
Disconnect the client from the server.
import { Meteor } from "meteor/meteor";
Meteor.disconnect();
Call this method to disconnect from the server and stop all live data updates. While the client is disconnected it will not receive updates to collections, method calls will be queued until the connection is reestablished, and hot code push will be disabled.
Call Meteor.reconnect to reestablish the connection and resume data transfer.
This can be used to save battery on mobile devices when real time updates are not required.
Meteor.onConnection Server only
Server only
Summary:
Register a callback to be called when a new DDP connection is made to the server.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | The function to call when a new DDP connection is established. | Yes |
import { Meteor } from "meteor/meteor";
const handle = Meteor.onConnection((connection) => {
console.log(connection);
// ^^^^^^^^^^^
// {
// id: String,
// close: Function,
// onClose: Function,
// clientAddress: String,
// httpHeaders: Object,
// }
});
handle.stop(); // Unregister the callback
onConnection
returns an object with a single method stop
. Calling stop
unregisters the callback, so that this callback will no longer be called on new connections.
The callback is called with a single argument, the server-side connection
representing the connection from the client. This object contains the following fields:
id
- String: A globally unique id for this connection.close
- Function: Close this DDP connection. The client is free to reconnect, but will receive a different connection with a newid
if it does.onClose
- Function: Register a callback to be called when the connection is closed. If the connection is already closed, the callback will be called immediately.clientAddress
- String: The IP address of the client in dotted form (such as127.0.0.1
). If you're running your Meteor server behind a proxy (so that clients are connecting to the proxy instead of to your server directly), you'll need to set theHTTP_FORWARDED_COUNT
environment variable for the correct IP address to be reported byclientAddress
.Set
HTTP_FORWARDED_COUNT
to an integer representing the number of proxies in front of your server. For example, you'd set it to1
when your server was behind one proxy.httpHeaders
- Object: When the connection came in over an HTTP transport (such as with Meteor's default SockJS implementation), this field contains whitelisted HTTP headers.Cookies are deliberately excluded from the headers as they are a security risk for this transport. For details and alternatives, see the SockJS documentation.
Currently when a client reconnects to the server (such as after temporarily losing its Internet connection), it will get a new connection each time. The
onConnection
callbacks will be called again, and the new connection will have a new connectionid
.
In the future, when client reconnection is fully implemented, reconnecting from the client will reconnect to the same connection on the server: the
onConnection
callback won't be called for that connection again, and the connection will still have the same connectionid
.
DDP.connect
Summary:
Connect to the server of a different Meteor application to subscribe to its document sets and invoke its remote methods.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
url | String | The URL of another Meteor application. | Yes |
options | Object | No |
import { DDP } from "meteor/ddp-client";
import { Mongo } from "meteor/mongo";
import { Meteor } from "meteor/meteor";
const options = {...};
const otherServer = DDP.connect("http://example.com", options);
otherServer.call("foo.from.other.server", 1, 2, function (err, result) {
// ...
});
Metepr.call("foo.from.this.server", 1, 2, function (err, result) {
// ...
});
const remoteColl = new Mongo.Collection("collectionName", { connection: otherServer });
remoteColl.find(...);
To call methods on another Meteor application or subscribe to its data sets, call DDP.connect
with the URL of the application. DDP.connect
returns an object which provides:
subscribe
- Subscribe to a record set. See Meteor.subscribe.call
- Invoke a method. See Meteor.call.apply
- Invoke a method with an argument array. See Meteor.apply.methods
- Define client-only stubs for methods defined on the remote server. See Meteor.methods.status
- Get the current connection status. See Meteor.status.reconnect
- See Meteor.reconnect.disconnect
- See Meteor.disconnect.
By default, clients open a connection to the server from which they're loaded. When you call Meteor.subscribe
, Meteor.status
, Meteor.call
, and Meteor.apply
, you are using a connection back to that default server.
DDP.onReconnect
Summary:
Register a function to call as the first step of reconnecting. This function can call methods which will be executed before any other outstanding methods. For example, this can be used to re-establish the appropriate authentication context on the connection.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
callback | function | The function to call. It will be called with a single argument, the connection object that is reconnecting. | Yes |
import { DDP } from "meteor/ddp-client";
DDP.onReconnect(
() => {}
);
Timers
Meteor uses global environment variables to keep track of things like the current request's user. To make sure these variables have the right values, you need to use Meteor.setTimeout
instead of setTimeout
and Meteor.setInterval
instead of setInterval
.
These functions work just like their native JavaScript equivalents. If you call the native function, you'll get an error stating that Meteor code must always run within a Fiber, and advising to use Meteor.bindEnvironment
.
Meteor.setTimeout
Summary:
Call a function in the future after waiting for a specified delay.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The function to run | Yes |
delay | Number | Number of milliseconds to wait before calling function | Yes |
import { Meteor } from "meteor/meteor";
Meteor.setTimeout(
() => {},
42,
);
Returns a handle that can be used by Meteor.clearTimeout
.
Meteor.setInterval
Summary:
Call a function repeatedly, with a time delay between calls.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | The function to run | Yes |
delay | Number | Number of milliseconds to wait between each function call. | Yes |
import { Meteor } from "meteor/meteor";
Meteor.setInterval(
() => {},
42,
);
Returns a handle that can be used by Meteor.clearInterval
.
Meteor.clearTimeout
Summary:
Cancel a function call scheduled by Meteor.setTimeout
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
id | Object | The handle returned by | Yes |
import { Meteor } from "meteor/meteor";
Meteor.clearTimeout(
id
);
Meteor.clearInterval
Summary:
Cancel a repeating function call scheduled by Meteor.setInterval
.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
id | Object | The handle returned by | Yes |
import { Meteor } from "meteor/meteor";
Meteor.clearInterval(
id
);
Enviroment variables
Meteor implements Meteor.EnvironmentVariable
with AsyncLocalStorage, which allows for maintaining context across asynchronous boundaries. Meteor.EnvironmentVariable
works with Meteor.bindEnvironment
, promises, and many other Meteor API's to preserve the context in async code. Some examples of how it is used in Meteor are to store the current user in methods, and record which arguments have been checked when using audit-argument-checks
.
import { Meteor } from "meteor/meteor";
const currentRequest = new Meteor.EnvironmentVariable();
function log(message) {
const requestId = currentRequest.get() || "None";
console.log(`[${requestId}]`, message);
}
currentRequest.withValue("12345", () => {
log("Handling request"); // Logs: [12345] Handling request
});
Meteor.EnvironmentVariable
Summary:
Constructor for EnvironmentVariable
import { Meteor } from "meteor/meteor"";
const environmentVariable = new Meteor.EnvironmentVariable();
);
Meteor.EnvironmentVariableAsync
Summary:
Constructor for EnvironmentVariable
import { Meteor } from "meteor/meteor"";
const environmentVariableAsync = new Meteor.EnvironmentVariableAsync();
);
Meteor.EnvironmentVariable.get
Summary:
Getter for the current value of the variable, or undefined
if
called from outside a withValue
callback.
import { Meteor } from "meteor/meteor";
/** @returns any */
const result = Meteor.EnvironmentVariable.get();
Meteor.EnvironmentVariable.withValue
Summary:
takes a value and a function, calls the function with the value set for the duration of the call
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
value | any | The value to set for the duration of the function call | Yes |
func | function | The function to call with the new value of the | Yes |
options | Object | Optional additional properties for adding in asl | No |
import { Meteor } from "meteor/meteor";
/** @returns Promise<any> */
const result = Meteor.EnvironmentVariable.withValue(
any,
() => {},
options, // this param is optional
);
Meteor.bindEnvironment
Summary:
Stores the current Meteor environment variables, and wraps the function to run with the environment variables restored. On the server, the function is wrapped within Async Local Storage.
This function has two reasons:
- Return the function to be executed on the MeteorJS context, having it assigned in Async Local Storage.
- Better error handling, the error message will be more clear.
Arguments:
Source codeName | Type | Description | Required |
---|---|---|---|
func | function | Function that is wrapped | Yes |
onException | function | ---- | Yes |
_this | Object | Optional | Yes |
import { Meteor } from "meteor/meteor";
/** @returns function */
const result = Meteor.bindEnvironment(
() => {},
() => {},
_this,
);