The data browser is built for Chrome, Firefox, Safari, and IE9 and above. Please upgrade your browser, or download Google Chrome to get the best experience.

JavaScript Guide

If you haven't set up your project yet, please head over to the QuickStart guide to get up and running. You can also check out our API Reference for more detailed information about our SDK.

Introduction

The Parse platform provides a complete backend solution for your mobile application. Our goal is to totally eliminate the need for writing server code or maintaining servers.

Our JavaScript SDK is based on the popular Backbone.js framework. It is compatible with existing Backbone applications with minimal changes on your part. Our goal is to minimize configuration and let you quickly start building your JavaScript and HTML5 app on Parse.

Our SDK supports Firefox 23+, Chrome 17+, Safari 5+, and IE 10. IE 8 and IE 9 are supported only for apps that are hosted with HTTPS.

Apps

On Parse, you create an App for each of your mobile applications. Each App has its own application id and JavaScript client key that you apply to your web app. Your account on Parse can accommodate multiple Apps. This is useful even if you have one application, since you can deploy different versions for test and production.

Dependencies

Our JavaScript SDK does not require any external libraries. The only exception is the Parse.View class, which requires that you provide jQuery or a jQuery compatible $ method.

Objects

Parse.Object

Storing data on Parse is built around Parse.Object. Each Parse.Object contains key-value pairs of JSON-compatible data. This data is schemaless, which means that you don't need to specify ahead of time what keys exist on each Parse.Object. You simply set whatever key-value pairs you want, and our backend will store it.

For example, let's say you're tracking high scores for a game. A single Parse.Object could contain:

score: 1337, playerName: "Sean Plott", cheatMode: false

Keys must be alphanumeric strings. Values can be strings, numbers, booleans, or even arrays and dictionaries - anything that can be JSON-encoded.

Each Parse.Object is an instance of a specific subclass with a class name that you can use to distinguish different sorts of data. For example, we could call the high score object a GameScore. We recommend that you NameYourClassesLikeThis and nameYourKeysLikeThis, just to keep your code looking pretty.

To create a new subclass, use the Parse.Object.extend method. Any Parse.Query will return instances of the new class for any Parse.Object with the same classname. If you're familiar with Backbone.Model, then you already know how to use Parse.Object. It's designed to be a drop-in replacement.

// Simple syntax to create a new subclass of Parse.Object.
var GameScore = Parse.Object.extend("GameScore");

// Create a new instance of that class.
var gameScore = new GameScore();

// Alternatively, you can use the typical Backbone syntax.
var Achievement = Parse.Object.extend({
  className: "Achievement"
});

You can add additional methods and properties to your subclasses of Parse.Object.

// A complex subclass of Parse.Object
var Monster = Parse.Object.extend("Monster", {
  // Instance methods
  hasSuperHumanStrength: function () {
    return this.get("strength") > 18;
  },
  // Instance properties go in an initialize method
  initialize: function (attrs, options) {
    this.sound = "Rawr"
  }
}, {
  // Class methods
  spawn: function(strength) {
    var monster = new Monster();
    monster.set("strength", strength);
    return monster;
  }
});

var monster = Monster.spawn(200);
alert(monster.strength());  // Displays 200.
alert(monster.sound); // Displays Rawr.

Saving Objects

Let's say you want to save the GameScore described above to the Parse Cloud. The interface is similar to a Backbone.Model, including the save method:

var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.set("cheatMode", false);

gameScore.save(null, {
  success: function(gameScore) {
    // Execute any logic that should take place after the object is saved.
    alert('New object created with objectId: ' + gameScore.id);
  },
  error: function(gameScore, error) {
    // Execute any logic that should take place if the save fails.
    // error is a Parse.Error with an error code and description.
    alert('Failed to create new object, with error code: ' + error.description);
  }
});

After this code runs, you will probably be wondering if anything really happened. To make sure the data was saved, you can look at the Data Browser in your app on Parse. You should see something like this:

objectId: "xWMyZ4YEGZ", score: 1337, playerName: "Sean Plott", cheatMode: false,
createdAt:"2011-06-10T18:33:42Z", updatedAt:"2011-06-10T18:33:42Z"

There are two things to note here. You didn't have to configure or set up a new Class called GameScore before running this code. Your Parse app lazily creates this Class for you when it first encounters it.

There are also a few fields you don't need to specify that are provided as a convenience. objectId is a unique identifier for each saved object. createdAt and updatedAt represent the time that each object was created and last modified in the cloud. Each of these fields is filled in by Parse, so they don't exist on a Parse.Object until a save operation has completed.

If you prefer, you can set attributes directly in your call to save instead.

var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.save({
  score: 1337,
  playerName: "Sean Plott",
  cheatMode: false
}, {
  success: function(gameScore) {
    // The object was saved successfully.
  },
  error: function(gameScore, error) {
    // The save failed.
    // error is a Parse.Error with an error code and description.
  }
});

Retrieving Objects

Saving data to the cloud is fun, but it's even more fun to get that data out again. If you have the objectId, you can retrieve the whole Parse.Object using a Parse.Query:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.get("xWMyZ4YEGZ", {
  success: function(gameScore) {
    // The object was retrieved successfully.
  },
  error: function(object, error) {
    // The object was not retrieved successfully.
    // error is a Parse.Error with an error code and description.
  }
});

To get the values out of the Parse.Object, use the get method.

var score = gameScore.get("score");
var playerName = gameScore.get("playerName");
var cheatMode = gameScore.get("cheatMode");

The three special values are provided as properties:

var objectId = gameScore.id;
var updatedAt = gameScore.updatedAt;
var createdAt = gameScore.createdAt;

If you need to refresh an object you already have with the latest data that is in the Parse Cloud, you can call the fetch method like so:

myObject.fetch({
  success: function(myObject) {
    // The object was refreshed successfully.
  },
  error: function(myObject, error) {
    // The object was not refreshed successfully.
    // error is a Parse.Error with an error code and description.
  }
});

Updating Objects

Updating an object is simple. Just set some new data on it and call the save method. For example:

// Create the object.
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();

gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.set("cheatMode", false);
gameScore.set("skills", ["pwnage", "flying"]);

gameScore.save(null, {
  success: function(gameScore) {
    // Now let's update it with some new data. In this case, only cheatMode and score
    // will get sent to the cloud. playerName hasn't changed.
    gameScore.set("cheatMode", true);
    gameScore.set("score", 1338);
    gameScore.save();
  }
});

Parse automatically figures out which data has changed so only "dirty" fields will be sent to the Parse Cloud. You don't need to worry about squashing data that you didn't intend to update.

Counters

The above example contains a common use case. The "score" field is a counter that we'll need to continually update with the player's latest score. Using the above method works but it's cumbersome and can lead to problems if you have multiple clients trying to update the same counter.

To help with storing counter-type data, Parse provides methods that atomically increment (or decrement) any number field. So, the same update can be rewritten as:

gameScore.increment("score");
gameScore.save();

You can also increment by any amount by passing in a second argument to increment. When no amount is specified, 1 is used by default.

Arrays

To help with storing array data, there are three operations that can be used to atomically change an array associated with a given key:

  • add append the given object to the end of an array field.
  • addUnique add the given object only if it isn't already contained in an array field. The position of the insert is not guaranteed.
  • remove remove all instances of the given object from an array field.

For example, we can add items to the set-like "skills" field like so:

gameScore.addUnique("skills", "flying");
gameScore.addUnique("skills", "kungfu");
gameScore.save();

Note that it is not currently possible to atomically add and remove items from an array in the same save. You will have to call save in between every different kind of array operation.

Destroying Objects

To delete an object from the cloud:

myObject.destroy({
  success: function(myObject) {
    // The object was deleted from the Parse Cloud.
  },
  error: function(myObject, error) {
    // The delete failed.
    // error is a Parse.Error with an error code and description.
  }
});

You can delete a single field from an object with the unset method:

// After this, the playerName field will be empty
myObject.unset("playerName");

// Saves the field deletion to the Parse Cloud
myObject.save();

Relational Data

Objects may have relationships with other objects. For example, in a blogging application, a Post object may have many Comment objects. Parse supports all kind of relationships, including one-to-one, one-to-many, and many-to-many.

One-to-One and One-to-Many Relationships

One-to-one and one-to-many relationships are modeled by saving a Parse.Object as a value in the other object. For example, each Comment in a blogging app might correspond to one Post.

To create a new Post with a single Comment, you could write:

// Declare the types.
var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");

// Create the post
var myPost = new Post();
myPost.set("title", "I'm Hungry");
myPost.set("content", "Where should we go for lunch?");

// Create the comment
var myComment = new Comment();
myComment.set("content", "Let's do Sushirrito.");

// Add the post as a value in the comment
myComment.set("parent", myPost);

// This will save both myPost and myComment
myComment.save();

Internally, the Parse framework will store the referred-to object in just one place, to maintain consistency. You can also link objects using just their objectIds like so:

var post = new Post();
post.id = "1zEcyElZ80";

myComment.set("parent", post);

By default, when fetching an object, related Parse.Objects are not fetched. These objects' values cannot be retrieved until they have been fetched like so:

var post = fetchedComment.get("parent");
post.fetch({
  success: function(post) {
    var title = post.get("title");
  }
});

Many-to-Many Relationships

Many-to-many relationships are modeled using Parse.Relation. This works similar to storing an array of Parse.Objects in a key, except that you don't need to fetch all of the objects in a relation at once. In addition, this allows Parse.Relation to scale to many more objects than the array of Parse.Object approach. For example, a User may have many Posts that she might like. In this case, you can store the set of Posts that a User likes using relation. In order to add a Post to the "likes" list of the User, you can do:

var user = Parse.User.current();
var relation = user.relation("likes");
relation.add(post);
user.save();

You can remove a post from a Parse.Relation:

relation.remove(post);
user.save();

You can call add and remove multiple times before calling save:

relation.remove(post1);
relation.remove(post2);
user.save();

You can also pass in an array of Parse.Object to add and remove:

relation.add([post1, post2, post3]);
user.save();

By default, the list of objects in this relation are not downloaded. You can get a list of the posts that a user likes by using the Parse.Query returned by query. The code looks like:

relation.query().find({
  success: function(list) {
    // list contains the posts that the current user likes.
  }
});

If you want only a subset of the Posts, you can add extra constraints to the Parse.Query returned by query like this:

var query = relation.query();
query.equalTo("title", "I'm Hungry");
query.find({
  success:function(list) {
    // list contains post liked by the current user which have the title "I'm Hungry".
  }
});

For more details on Parse.Query, please look at the query portion of this guide. A Parse.Relation behaves similar to an array of Parse.Object for querying purposes, so any query you can do on an array of objects, you can do on a Parse.Relation.

Data Types

So far we've used values with type String, Number, and Parse.Object. Parse also supports JavaScript Dates and null.

You can nest JavaScript Objects and JavaScript Arrays to store more structured data within a single Parse.Object.

Some examples:

var number = 42;
var string = "the number is " + number;
var date = new Date();
var array = [string, number];
var object = { number: number, string: string };

var BigObject = Parse.Object.extend("BigObject");
var bigObject = new BigObject();
bigObject.set("myNumber", number);
bigObject.set("myString", string);
bigObject.set("myDate", date);
bigObject.set("myArray", array);
bigObject.set("myObject", object);
bigObject.set("myNull", null);
bigObject.save();

Parse.Objects should not exceed 128 kilobytes in size.

For more information about how Parse handles data, check out our documentation on Data & Security.

Queries

We've already seen how a Parse.Query with get can retrieve a single Parse.Object from Parse. There are many other ways to retrieve data with Parse.Query - you can retrieve many objects at once, put conditions on the objects you wish to retrieve, and more.

Basic Queries

In many cases, get isn't powerful enough to specify which objects you want to retrieve. Parse.Query offers different ways to retrieve a list of objects rather than just a single object.

The general pattern is to create a Parse.Query, put conditions on it, and then retrieve an Array of matching Parse.Objects using find. For example, to retrieve of the scores with a particular playerName, use the equalTo method to constrain the value for a key.

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Dan Stemkoski");
query.find({
  success: function(results) {
    alert("Successfully retrieved " + results.length + " scores.");
    // Do something with the returned Parse.Object values
    for (var i = 0; i < results.length; i++) { 
      var object = results[i];
      alert(object.id + ' - ' + object.get('playerName'));
    }
  },
  error: function(error) {
    alert("Error: " + error.code + " " + error.message);
  }
});

Query Constraints

There are several ways to put constraints on the objects found by a Parse.Query. You can filter out objects with a particular key-value pair with notEqualTo:

query.notEqualTo("playerName", "Michael Yabuti");

You can give multiple constraints, and objects will only be in the results if they match all of the constraints. In other words, it's like an AND of constraints.

query.notEqualTo("playerName", "Michael Yabuti");
query.greaterThan("playerAge", 18);

You can limit the number of results by setting limit. By default, results are limited to 100, but anything from 1 to 1000 is a valid limit:

query.limit(10); // limit to at most 10 results

If you want exactly one result, a more convenient alternative may be to use first instead of using find.

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerEmail", "dstemkoski@example.com");
query.first({
  success: function(object) {
    // Successfully retrieved the object.
  },
  error: function(error) {
    alert("Error: " + error.code + " " + error.message);
  }
});

You can skip the first results by setting skip. This can be useful for pagination:

query.skip(10); // skip the first 10 results

For sortable types like numbers and strings, you can control the order in which results are returned:

// Sorts the results in ascending order by the score field
query.ascending("score");

// Sorts the results in descending order by the score field
query.descending("score");

For sortable types, you can also use comparisons in queries:

// Restricts to wins < 50
query.lessThan("wins", 50);

// Restricts to wins <= 50
query.lessThanOrEqualTo("wins", 50);

// Restricts to wins > 50
query.greaterThan("wins", 50);

// Restricts to wins >= 50
query.greaterThanOrEqualTo("wins", 50);

If you want to retrieve objects matching several different values, you can use containedIn, providing an array of acceptable values. This is often useful to replace multiple queries with a single query. For example, if you want to retrieve scores made by any player in a particular list:

// Finds scores from any of Jonathan, Dario, or Shawn
query.containedIn("playerName",
                  ["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);

If you want to retrieve objects that do not match any of several values you can use notContainedIn, providing an array of acceptable values. For example if you want to retrieve scores from players besides those in a list:

// Finds scores from anyone who is neither Jonathan, Dario, nor Shawn
query.notContainedIn("playerName",
                     ["Jonathan Walsh", "Dario Wunsch", "Shawn Simon"]);

If you want to retrieve objects that have a particular key set, you can use exists. Conversely, if you want to retrieve objects without a particular key set, you can use doesNotExist.

// Finds objects that have the score set
query.exists("score");

// Finds objects that don't have the score set
query.doesNotExist("score");

You can use the matchesKeyInQuery method to get objects where a key matches the value of a key in a set of objects resulting from another query. For example, if you have a class containing sports teams and you store a user's hometown in the user class, you can issue one query to find the list of users whose hometown teams have winning records. The query would look like:

var Team = Parse.Object.extend("Team");
var teamQuery = new Parse.Query(Team);
teamQuery.greaterThan("winPct", 0.5);
var userQuery = new Parse.Query(Parse.User);
userQuery.matchesKeyInQuery("hometown", "city", teamQuery);
userQuery.find({ 
  success: function(results) {
    // results has the list of users with a hometown team with a winning record
  }
});

Conversely, to get objects where a key does not match the value of a key in a set of objects resulting from another query, use doesNotMatchKeyInQuery. For example, to find users whose hometown teams have losing records:

var losingUserQuery = new Parse.Query(Parse.User);
losingUserQuery.doesNotMatchKeyInQuery("hometown", "city", teamQuery);
losingUserQuery.find({
  success: function(results) {
    // results has the list of users with a hometown team with a losing record
  }
});

You can restrict the fields returned by calling select with a list of keys. To retrieve documents that contain only the score and playerName fields (and also special built-in fields such as objectId, createdAt, and updatedAt):

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.select("score", "playerName");
query.find().then(function(results) {
  // each of results will only have the selected fields available.
});

The remaining fields can be fetched later by calling fetch on the returned objects:

query.first().then(function(result) {
  // only the selected fields of the object will now be available here.
  return result.fetch();
}).then(function(result) {
  // all fields of the object will now be available here.
});

Queries on Array Values

For keys with an array type, you can find objects where the key's array value contains 2 by:

// Find objects where the array in arrayKey contains 2.
query.equalTo("arrayKey", 2);

You can also find objects where the key's array value contains each of the elements 2, 3, and 4 with the following:

// Find objects where the array in arrayKey contains all of the elements 2, 3, and 4.
query.containsAll("arrayKey", [2, 3, 4]);

Queries on String Values

Use startsWith to restrict to string values that start with a particular string. Similar to a MySQL LIKE operator, this is indexed so it is efficient for large datasets:

// Finds barbecue sauces that start with "Big Daddy's".
var query = new Parse.Query(BarbecueSauce);
query.startsWith("name", "Big Daddy's");

Relational Queries

There are several ways to issue queries for relational data. If you want to retrieve objects where a field matches a particular Parse.Object, you can use equalTo just like for other data types. For example, if each Comment has a Post object in its post field, you can fetch comments for a particular Post:

// Assume Parse.Object myPost was previously created.
var query = new Parse.Query(Comment);
query.equalTo("post", myPost);
query.find({
  success: function(comments) {
    // comments now contains the comments for myPost
  }
});

If you want to retrieve objects where a field contains a Parse.Object that matches a different query, you can use matchesQuery. Note that the default limit of 100 and maximum limit of 1000 apply to the inner query as well, so with large data sets you may need to construct queries carefully to get the desired behavior. In order to find comments for posts containing images, you can do:

var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
var innerQuery = new Parse.Query(Post);
innerQuery.exists("image");
var query = new Parse.Query(Comment);
query.matchesQuery("post", innerQuery);
query.find({
  success: function(comments) {
    // comments now contains the comments for posts with images.
  }
});

If you want to retrieve objects where a field contains a Parse.Object that does not match a different query, you can use doesNotMatchQuery. In order to find comments for posts without images, you can do:

var Post = Parse.Object.extend("Post");
var Comment = Parse.Object.extend("Comment");
var innerQuery = new Parse.Query(Post);
innerQuery.exists("image");
var query = new Parse.Query(Comment);
query.doesNotMatchQuery("post", innerQuery);
query.find({
  success: function(comments) {
    // comments now contains the comments for posts without images.
  }
});

You can also do relational queries by objectId:

var post = new Post();
post.id = "1zEcyElZ80";
query.equalTo("post", post);

In some situations, you want to return multiple types of related objects in one query. You can do this with the include method. For example, let's say you are retrieving the last ten comments, and you want to retrieve their related posts at the same time:

var query = new Parse.Query(Comment);

// Retrieve the most recent ones
query.descending("createdAt");

// Only retrieve the last ten
query.limit(10);

// Include the post data with each comment
query.include("post");

query.find({
  success: function(comments) {
    // Comments now contains the last ten comments, and the "post" field
    // has been populated. For example:
    for (var i = 0; i < comments.length; i++) {
      // This does not require a network access.
      var post = comments[i].get("post");
    }
  }
});

You can also do multi level includes using dot notation. If you wanted to include the post for a comment and the post's author as well you can do:

query.include(["post.author"]);

You can issue a query with multiple fields included by calling include multiple times. This functionality also works with Parse.Query helpers like first and get.

Counting Objects

If you just need to count how many objects match a query, but you do not need to retrieve all the objects that match, you can use count instead of find. For example, to count how many games have been played by a particular player:

var GameScore = Parse.Object.extend("GameScore");
var query = new Parse.Query(GameScore);
query.equalTo("playerName", "Sean Plott");
query.count({
  success: function(count) {
    // The count request succeeded. Show the count
    alert("Sean has played " + count + " games");
  },
  error: function(error) {
    // The request failed
  }
});

For classes with over 1000 objects, count operations are limited by timeouts. They may routinely yield timeout errors or return results that are only approximately correct. Thus, it is preferable to architect your application to avoid this sort of count operation.

Compound Queries

If you want to find objects that match one of several queries, you can use Parse.Query.or method to construct a query that is an OR of the queries passed in. For instance if you want to find players who either have a lot of wins or a few wins, you can do:

var lotsOfWins = new Parse.Query("Player");
lotsOfWins.greaterThan("wins", 150);

var fewWins = new Parse.Query("Player");
fewWins.lessThan("wins", 5);

var mainQuery = Parse.Query.or(lotsOfWins, fewWins);
mainQuery.find({
  success: function(results) {
     // results contains a list of players that either have won a lot of games or won only a few games.
  },
  error: function(error) {
    // There was an error.
  }
});

You can add additional constraints to the newly created Parse.Query that act as an 'and' operator.

Note that we do not, however, support non-filtering constraints (e.g. limit, skip, ascending/descending, include) in the subqueries of the compound query.

Promises

In addition to callbacks, every asynchronous method in the Parse JavaScript SDK returns a Promise. With promises, your code can be much cleaner than the nested code you get with callbacks.

The then Method

   

Every Promise has a method named then which takes a pair of callbacks. The first callback is called if the promise is resolved, while the second is called if the promise is rejected.

obj.save().then(function(obj) {
  // the object was saved successfully.
}, function(error) {
  // the save failed.
});

Chaining Promises Together

Promises are a little bit magical, in that they let you chain them without nesting. If a callback for a promise returns a new promise, then the first one will not be resolved until the second one is. This lets you perform multiple actions without incurring the pyramid code you would get with callbacks.

var query = new Parse.Query("Student");
query.descending("gpa");
query.find().then(function(students) {
  students[0].set("valedictorian", true);
  return students[0].save();

}).then(function(valedictorian) {
  return query.find();

}).then(function(students) {
  students[1].set("salutatorian", true);
  return students[1].save();

}).then(function(salutatorian) {
  // Everything is done!

});

Error Handling

If any Promise in a chain returns an error, all of the success callbacks after it will be skipped until an error callback is encountered. The error callback can transform the error, or it can handle it by returning a new Promise that isn't rejected. You can think of rejected promises kind of like throwing an exception. An error callback is like a catch block that can handle the error or rethrow it.

var query = new Parse.Query("Student");
query.descending("gpa");
query.find().then(function(students) {
  students[0].set("valedictorian", true);
  // Force this callback to fail.
  return Parse.Promise.error("There was an error.");

}).then(function(valedictorian) {
  // Now this will be skipped.
  return query.find();

}).then(function(students) {
  // This will also be skipped.
  students[1].set("salutatorian", true);
  return students[1].save();
}, function(error) {
  // This error handler WILL be called. error will be "There was an error.".
  // Let's handle the error by returning a new promise.
  return Parse.Promise.as("Hello!");

}).then(function(hello) {
  // Everything is done!
}, function(error) {
  // This isn't called because the error was already handled.
});

It's often convenient to have a long chain of success callbacks with only one error handler at the end.

Creating Promises

When you're getting started, you can just use the promises returned from methods like find or save. However, for more advanced scenarios, you may want to make your own promises. After you create a Promise, you'll need to call resolve or reject to trigger its callbacks.

var successful = new Parse.Promise();
successful.resolve("The good result.");

var failed = new Parse.Promise();
failed.reject("An error message.");

If you know the result of a promise at the time it is created, there are some convenience methods you can use.

var successful = Parse.Promise.as("The good result.");

var failed = Parse.Promise.error("An error message.");

Promises in Series

Promises are convenient when you want to do a series of tasks in a row, each one waiting for the previous to finish. For example, imagine you want to delete all of the comments on your blog.

var query = new Parse.Query("Comments");
query.equalTo("post", 123);

query.find().then(function(results) {
  // Create a trivial resolved promise as a base case.
  var promise = Parse.Promise.as();
  _.each(results, function(result) {
    // For each item, extend the promise with a function to delete it.
    promise = promise.then(function() {
      // Return a promise that will be resolved when the delete is finished.
      return result.destroy();
    });
  });
  return promise;

}).then(function() {
  // Every comment was deleted.
});

Promises in Parallel

You can also use promises to perform several tasks in parallel, using the when method. You can start multiple operations at once, and use Parse.Promise.when to create a new promise that will be resolved when all of its input promises is resolved. The new promise will be successful even if some of the passed-in promises fail. You can inspect the result of each promise in the argument to its callback. Performing operations in parallel will be faster than doing them serially, but may consume more system resources and bandwidth.

var query = new Parse.Query("Comments");
query.equalTo("post", 123);

query.find().then(function(results) {
  // Collect one promise for each delete into an array.
  var promises = [];
  _.each(results, function(result) {
    // Start this delete immediately and add its promise to the list.
    promises.push(result.destroy());
  });
  // Return a new promise that is resolved when all of the deletes are finished.
  return Parse.Promise.when(promises);

}).then(function() {
  // Every comment was deleted.
});

Creating Async Methods

With these tools, it's easy to make your own asynchronous functions that return promises. For example, you can make a promisified version of setTimeout.

var delay = function(millis) {
  var promise = new Parse.Promise();
  setTimeout(function() {
    promise.resolve();
  }, millis);
  return promise;
};

delay(100).then(function() {
  // This ran after 100ms!
});

Collections

A Parse.Collection is an ordered set of Parse.Objects. It is compatible with Backbone.Collection, and has all the same functionality. You can create a new subclass using either a model class, or a particular Parse.Query.

// A Collection containing all instances of TestObject.
var TestCollection = Parse.Collection.extend({
  model: TestObject
});
var collection = new TestCollection();

// A Collection of TestObjects whose temperature is "hot".
var HotCollection = Parse.Collection.extend({
  model: TestObject,
  query: (new Parse.Query(TestObject)).equalTo("temperature", "hot")
});
var collection = new HotCollection();

// The Collection of TestObjects that match a complex query.
var query = new Parse.Query(TestObject);
query.equalTo("temperature", "hot");
query.greaterThan("degreesF", 100);
var collection = query.collection();

Retrieving Collections

To load all of the items in the collection, use the fetch method.

var collection = new TestCollection();
collection.fetch({
  success: function(collection) {
    collection.each(function(object) {
      console.warn(object);
    });
  },
  error: function(collection, error) {
    // The collection could not be retrieved.
  }
});

Sorting Collections

You can keep all the items in a collection in a sorted order by setting a comparator.

var collection = new TestCollection();
collection.comparator = function(object) {
  return object.get("temperature");
};

Modifying a Collection

Collections are mutable. You can access all the items, and add or remove items.

var collection = new TestCollection();

collection.add([
  {"name": "Duke"},
  {"name": "Scarlett"}
]);

// Get the "Duke" Parse.Object by its sorted position.
var model = collection.at(0);

// Or you can get it by Parse objectId.
var modelAgain = collection.get(model.id);

// Remove "Duke" from the collection.
collection.remove(model);

// Completely replace all items in the collection.
collection.reset([
  {"name": "Hawk"},
  {"name": "Jane"}
]);

Files

Creating a Parse.File

Parse.File lets you store application files in the cloud that would otherwise be too large or cumbersome to fit into a regular Parse.Object. The most common use case is storing images, but you can also use it for documents, videos, music, and any other binary data (up to 10 megabytes).

Getting started with Parse.File is easy. There are a couple of ways to create a file. The first is with a base64-encoded String.

var base64 = "V29ya2luZyBhdCBQYXJzZSBpcyBncmVhdCE=";
var file = new Parse.File("myfile.txt", { base64: base64 });

Alternatively, you can create a file from an array of byte values:

var bytes = [ 0xBE, 0xEF, 0xCA, 0xFE ];
var file = new Parse.File("myfile.txt", bytes);

Parse will auto-detect the type of file you are uploading based on the file extension, but you can specify the Content-Type with a third parameter:

var file = new Parse.File("myfile.zzz", fileData, "image/png");

But most commonly for HTML5 apps, you'll want to use an html form with a file upload control. On modern browsers, this is easy. Create a file input tag which allows the user to pick a file from their local drive to upload:

<input type="file" id="profilePhotoFileUpload">

Then, in a click handler or other function, get a reference to that file:

var fileUploadControl = $("#profilePhotoFileUpload")[0];
if (fileUploadControl.files.length > 0) {
  var file = fileUploadControl.files[0];
  var name = "photo.jpg";

  var parseFile = new Parse.File(name, file);
}

Notice in this example that we give the file a name of photo.jpg. There's two things to note here:

  • You don't need to worry about filename collisions. Each upload gets a unique identifier so there's no problem with uploading multiple files named photo.jpg.
  • It's important that you give a name to the file that has a file extension. This lets Parse figure out the file type and handle it accordingly. So, if you're storing PNG images, make sure your filename ends with .png.

Next you'll want to save the file up to the cloud. As with Parse.Object, there are many variants of the save method you can use depending on what sort of callback and error handling suits you.

parseFile.save().then(function() {
  // The file has been saved to Parse.
}, function(error) {
  // The file either could not be read, or could not be saved to Parse.
});

Finally, after the save completes, you can associate a Parse.File with a Parse.Object just like any other piece of data:

var jobApplication = new Parse.Object("JobApplication");
jobApplication.set("applicantName", "Joe Smith");
jobApplication.set("applicantResumeFile", file);
jobApplication.save();

Retrieving File Contents

How to best retrieve the file contents back depends on the context of your application. Because of cross-domain request issues, it's best if you can make the browser do the work for you. Typically, that means rendering the file's URL into the DOM. Here we render an uploaded profile photo on a page with jQuery:

var profilePhoto = profile.get("photoFile");
$("profileImg")[0].src = profilePhoto.url();

If you want to process a File's data in Cloud Code, you can retrieve the file using our http networking libraries:

Parse.Cloud.httpRequest({ url: profilePhoto.url() }).then(function(response) {
  // The file contents are in response.buffer.
});

You can delete files that are referenced by objects using the REST API. You will need to provide the master key in order to be allowed to delete a file.

If your files are not referenced by any object in your app, it is not possible to delete them through the REST API. You may request a cleanup of unused files in your app's Settings page. Keep in mind that doing so may break functionality which depended on accessing unreferenced files through their URL property. Files that are currently associated with an object will not be affected.

Analytics

Parse provides a number of hooks for you to get a glimpse into the ticking heart of your app. We understand that it's important to understand what your app is doing, how frequently, and when.

While this section will cover different ways to instrument your app to best take advantage of Parse's analytics backend, developers using Parse to store and retrieve data can already take advantage of metrics on Parse.

Without having to implement any client-side logic, you can view real-time graphs and breakdowns (by device type, Parse class name, or REST verb) of your API Requests in your app's dashboard and save these graph filters to quickly access just the data you're interested in.

Custom Analytics

Parse.Analytics also allows you to track free-form events, with a handful of string keys and values. These extra dimensions allow segmentation of your custom events via your app's Dashboard.

Say your app offers search functionality for apartment listings, and you want to track how often the feature is used, with some additional metadata.

var dimensions = {
  // Define ranges to bucket data points into meaningful segments
  priceRange: '1000-1500',
  // Did the user filter the query?
  source: 'craigslist',
  // Do searches happen more often on weekdays or weekends?
  dayType: 'weekday'
};
// Send the dimensions to Parse along with the 'search' event
Parse.Analytics.track('search', dimensions)

Parse.Analytics can even be used as a lightweight error tracker — simply invoke the following and you'll have access to an overview of the rate and frequency of errors, broken down by error code, in your application:

var codeString = '' + error.code;
Parse.Analytics.track('error', { code: codeString });

Note that Parse currently only stores the first eight dimension pairs per call to Parse.Analytics.track().

Users

At the core of many apps, there is a notion of user accounts that lets users access their information in a secure manner. We provide a specialized user class called Parse.User that automatically handles much of the functionality required for user account management.

With this class, you'll be able to add user account functionality in your app.

Parse.User is a subclass of Parse.Object, and has all the same features, such as flexible schema, automatic persistence, and a key value interface. All the methods that are on Parse.Object also exist in Parse.User. The difference is that Parse.User has some special additions specific to user accounts.

Properties

Parse.User has several values that set it apart from Parse.Object:

  • username: The username for the user (required).
  • password: The password for the user (required on signup).
  • email: The email address for the user (optional).

We'll go through each of these in detail as we run through the various use cases for users.

Signing Up

The first thing your app will do is probably ask the user to sign up. The following code illustrates a typical sign up:

var user = new Parse.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("email", "email@example.com");

// other fields can be set just like with Parse.Object
user.set("phone", "415-392-0202");

user.signUp(null, {
  success: function(user) {
    // Hooray! Let them use the app now.
  },
  error: function(user, error) {
    // Show the error message somewhere and let the user try again.
    alert("Error: " + error.code + " " + error.message);
  }
});

This call will asynchronously create a new user in your Parse App. Before it does this, it also checks to make sure that both the username and email are unique. Also, it securely hashes the password in the cloud. We never store passwords in plaintext, nor will we ever transmit passwords back to the client in plaintext.

Note that we used the signUp method, not the save method. New Parse.Users should always be created using the signUp method. Subsequent updates to a user can be done by calling save.

If a signup isn't successful, you should read the error object that is returned. The most likely case is that the username or email has already been taken by another user. You should clearly communicate this to your users, and ask them try a different username.

You are free to use an email address as the username. Simply ask your users to enter their email, but fill it in the username property — Parse.User will work as normal. We'll go over how this is handled in the reset password section.

Logging In

Of course, after you allow users to sign up, you need to let them log in to their account in the future. To do this, you can use the class method logIn.

Parse.User.logIn("myname", "mypass", {
  success: function(user) {
    // Do stuff after successful login.
  },
  error: function(user, error) {
    // The login failed. Check error to see why.
  }
});

Verifying Emails

Enabling email verification in an application's settings allows the application to reserve part of its experience for users with confirmed email addresses. Email verification adds the emailVerified key to the Parse.User object. When a Parse.User's email is set or modified, emailVerified is set to false. Parse then emails the user a link which will set emailVerified to true.

There are three emailVerified states to consider:

  1. true - the user confirmed his or her email address by clicking on the link Parse emailed them. Parse.Users can never have a true value when the user account is first created.
  2. false - at the time the Parse.User object was last refreshed, the user had not confirmed his or her email address. If emailVerified is false, consider calling fetch on the Parse.User.
  3. missing - the Parse.User was created when email verification was off or the Parse.User does not have an email.

Current User

It would be bothersome if the user had to log in every time they open your app. You can avoid this by using the cached current Parse.User object.

Whenever you use any signup or login methods, the user is cached in localStorage. You can treat this cache as a session, and automatically assume the user is logged in:

var currentUser = Parse.User.current();
if (currentUser) {
    // do stuff with the user
} else {
    // show the signup or login page
}

You can clear the current user by logging them out:

Parse.User.logOut();

var currentUser = Parse.User.current();  // this will now be null

Setting the Current User

If you’ve created your own authentication routines, or otherwise logged in a user on the server side, you can now pass the session token to the client and use the become method. This method will ensure the session token is valid before setting the current user.

Parse.User.become("session-token-here").then(function (user) {
  // The current user is now set to user.
}, function (error) {
  // The token could not be validated.
});

Security For User Objects

The Parse.User class is secured by default. Data stored in a Parse.User can only be modified by that user. By default, the data can still be read by any client. Thus, some Parse.User objects are authenticated and can be modified, whereas others are read-only.

Specifically, you are not able to invoke any of the save or delete methods unless the Parse.User was obtained using an authenticated method, like logIn or signUp. This ensures that only the user can alter their own data.

The following illustrates this security policy:

var user = Parse.User.logIn("my_username", "my_password", {
  success: function(user) {
    user.set("username", "my_new_username");  // attempt to change username
    user.save(null, {
      success: function(user) {
        // This succeeds, since the user was authenticated on the device

        // Get the user from a non-authenticated method
        var query = new Parse.Query(Parse.User);
        query.get(user.objectId, {
          success: function(userAgain) {
            userAgain.set("username", "another_username");
            userAgain.save(null, {
              error: function(userAgain, error) {
                // This will error, since the Parse.User is not authenticated
              }
            });
          }
        });
      }
    });
  }
});

The Parse.User obtained from Parse.User.current() will always be authenticated.

If you need to check if a Parse.User is authenticated, you can invoke the authenticated method. You do not need to check authenticated with Parse.User objects that are obtained via an authenticated method.

Security For Other Objects

The same security model that applies to the Parse.User can be applied to other objects. For any object, you can specify which users are allowed to read the object, and which users are allowed to modify an object. To support this type of security, each object has an access control list, implemented by the Parse.ACL class.

The simplest way to use a Parse.ACL is to specify that an object may only be read or written by a single user. To create such an object, there must first be a logged in Parse.User. Then, new Parse.ACL(user) generates a Parse.ACL that limits access to that user. An object's ACL is updated when the object is saved, like any other property. Thus, to create a private note that can only be accessed by the current user:

var Note = Parse.Object.extend("Note");
var privateNote = new Note();
privateNote.set("content", "This note is private!");
privateNote.setACL(new Parse.ACL(Parse.User.current()));
privateNote.save();

This note will then only be accessible to the current user, although it will be accessible to any device where that user is signed in. This functionality is useful for applications where you want to enable access to user data across multiple devices, like a personal todo list.

Permissions can also be granted on a per-user basis. You can add permissions individually to a Parse.ACL using setReadAccess and setWriteAccess. For example, let's say you have a message that will be sent to a group of several users, where each of them have the rights to read and delete that message:

var Message = Parse.Object.extend("Message");
var groupMessage = new Message();
var groupACL = new Parse.ACL();

// userList is an array with the users we are sending this message to.
for (var i = 0; i < userList.length; i++) {
  groupACL.setReadAccess(userList[i], true);
  groupACL.setWriteAccess(userList[i], true);
}

groupMessage.setACL(groupACL);
groupMessage.save();

You can also grant permissions to all users at once using setPublicReadAccess and setPublicWriteAccess. This allows patterns like posting comments on a message board. For example, to create a post that can only be edited by its author, but can be read by anyone:

var publicPost = new Post();
var postACL = new Parse.ACL(Parse.User.current());
postACL.setPublicReadAccess(true);
publicPost.setACL(postACL);
publicPost.save();

Operations that are forbidden, such as deleting an object that you do not have write access to, result in a Parse.Error.OBJECT_NOT_FOUND error code. For security purposes, this prevents clients from distinguishing which object ids exist but are secured, versus which object ids do not exist at all.

Resetting Passwords

It's a fact that as soon as you introduce passwords into a system, users will forget them. In such cases, our library provides a way to let them securely reset their password.

To kick off the password reset flow, ask the user for their email address, and call:

Parse.User.requestPasswordReset("email@example.com", {
  success: function() {
	// Password reset request was sent successfully
  },
  error: function(error) {
    // Show the error message somewhere
    alert("Error: " + error.code + " " + error.message);
  }
});

This will attempt to match the given email with the user's email or username field, and will send them a password reset email. By doing this, you can opt to have users use their email as their username, or you can collect it separately and store it in the email field.

The flow for password reset is as follows:

  1. User requests that their password be reset by typing in their email.
  2. Parse sends an email to their address, with a special password reset link.
  3. User clicks on the reset link, and is directed to a special Parse page that will allow them type in a new password.
  4. User types in a new password. Their password has now been reset to a value they specify.

Note that the messaging in this flow will reference your app by the name that you specified when you created this app on Parse.

Querying

To query for users, you can simple create a new Parse.Query for Parse.Users:

var query = new Parse.Query(Parse.User);
query.equalTo(gender, "female");  // find all the women
query.find({
  success: function(women) {
    // Do stuff
  }
});

Associations

Associations involving a Parse.User work right of the box. For example, let's say you're making a blogging app. To store a new post for a user and retrieve all their posts:

var user = Parse.User.current();

// Make a new post
var Post = Parse.Object.extend("Post");
var post = new Post();
post.set("title", "My New Post");
post.set("body", "This is some great content.");
post.set("user", user);
post.save(null, {
  success: function(post) {
    // Find all posts by the current user
    var query = new Parse.Query(Post);
    query.equalTo("user", user);
    query.find({
      success: function(usersPosts) {
        // userPosts contains all of the posts by the current user.
      }
    });
  }
});

Users in the Data Browser

The User class is a special class that is dedicated to storing Parse.User objects. In the data browser, you'll see a little person icon next to the User class:

User_icon

Roles

As your app grows in scope and user-base, you may find yourself needing more coarse-grained control over access to pieces of your data than user-linked ACLs can provide. To address this requirement, Parse supports a form of Role-based Access Control. Roles provide a logical way of grouping users with common access privileges to your Parse data. Roles are named objects that contain users and other roles. Any permission granted to a role is implicitly granted to its users as well as to the users of any roles that it contains.

For example, in your application with curated content, you may have a number of users that are considered "Moderators" and can modify and delete content created by other users. You may also have a set of users that are "Administrators" and are allowed all of the same privileges as Moderators, but can also modify the global settings for the application. By adding users to these roles, you can ensure that new users can be made moderators or administrators, without having to manually grant permission to every resource for each user.

We provide a specialized class called Parse.Role that represents these role objects in your client code. Parse.Role is a subclass of Parse.Object, and has all of the same features, such as a flexible schema, automatic persistence, and a key value interface. All the methods that are on Parse.Object also exist on Parse.Role. The difference is that Parse.Role has some additions specific to management of roles.

Properties

Parse.Role has several properties that set it apart from Parse.Object:

  • name: The name for the role. This value is required, and can only be set once as a role is being created. The name must consist of alphanumeric characters, spaces, -, or _. This name will be used to identify the Role without needing its objectId.
  • users: A relation to the set of users that will inherit permissions granted to the containing role.
  • roles: A relation to the set of roles whose users and roles will inherit permissions granted to the containing role.

Security for Role Objects

The Parse.Role uses the same security scheme (ACLs) as all other objects on Parse, except that it requires an ACL to be set explicitly. Generally, only users with greatly elevated privileges (e.g. a master user or Administrator) should be able to create or modify a Role, so you should define its ACLs accordingly. Remember, if you give write-access to a Parse.Role to a user, that user can add other users to the role, or even delete the role altogether.

To create a new Parse.Role, you would write:

// By specifying no write privileges for the ACL, we can ensure the role cannot be altered.
var roleACL = new Parse.ACL();
roleACL.setPublicReadAccess(true);
var role = new Parse.Role("Administrator", roleACL);
role.save();

You can add users and roles that should inherit your new role's permissions through the "users" and "roles" relations on Parse.Role:

var role = new Parse.Role(roleName, roleACL);
for (var i = 0; i < usersToAddToRole.length; i++) {
  role.getUsers().add(usersToAddToRole[i]);
}
for (var i = 0; i < rolesToAddToRole.length; i++) {
  role.getRoles().add(rolesToAddToRole[i]);
}
role.save();

Take great care when assigning ACLs to your roles so that they can only be modified by those who should have permissions to modify them.

Security for Other Objects

Now that you have created a set of roles for use in your application, you can use them with ACLs to define the privileges that their users will receive. Each Parse.Object can specify a Parse.ACL, which provides an access control list that indicates which users and roles should be granted read or write access to the object.

Giving a role read or write permission to an object is straightforward. You can either use the Parse.Role:

var moderators = /* Query for some Parse.Role */;
var wallPost = new Parse.Object("WallPost");
var postACL = new Parse.ACL();
postACL.setRoleWriteAccess(moderators, true);
wallPost.setACL(postACL);
wallPost.save();

You can avoid querying for a role by specifying its name for the ACL:

var wallPost = new Parse.Object("WallPost");
var postACL = new Parse.ACL();
postACL.setRoleWriteAccess("Moderators", true);
wallPost.setACL(postACL);
wallPost.save();

Role Hierarchy

As described above, one role can contain another, establishing a parent-child relationship between the two roles. The consequence of this relationship is that any permission granted to the parent role is implicitly granted to all of its child roles.

These types of relationships are commonly found in applications with user-managed content, such as forums. Some small subset of users are "Administrators", with the highest level of access to tweaking the application's settings, creating new forums, setting global messages, and so on. Another set of users are "Moderators", who are responsible for ensuring that the content created by users remains appropriate. Any user with Administrator privileges should also be granted the permissions of any Moderator. To establish this relationship, you would make your "Administrators" role a child role of "Moderators", like this:

var administrators = /* Your "Administrators" role */;
var moderators = /* Your "Moderators" role */;
moderators.getRoles().add(administrators);
moderators.save();

Facebook Users

Parse provides an easy way to integrate Facebook with your application. The Parse.FacebookUtils class integrates Parse.User and the Facebook Javascript SDK to make linking your users to their Facebook identities easy.

Using our Facebook integration, you can associate an authenticated Facebook user with a Parse.User. With just a few lines of code, you'll be able to provide a "log in with Facebook" option in your app, and be able to save their data to Parse.

Setup

To start using Facebook with Parse, you need to:

  1. Set up a Facebook app, if you haven't already. Choose the "Website with Facebook Login" option under "Select how your app integrates with Facebook" and enter your site's URL.
  2. Add your application's Facebook Application ID on your Parse application's settings page.
  3. Follow these instructions for loading the Facebook Javascript SDK into your application.
  4. Replace your call to FB.init() with a call to Parse.FacebookUtils.init(). For example, if you loaded the Facebook SDK asynchronously, your fbAsyncInit function will look like this:
    window.fbAsyncInit = function() {
      Parse.FacebookUtils.init({
        appId      : 'YOUR_APP_ID', // Facebook App ID
        channelUrl : '//WWW.YOUR_DOMAIN.COM/channel.html', // Channel File
        status     : true, // check login status
        cookie     : true, // enable cookies to allow Parse to access the session
        xfbml      : true  // parse XFBML
      });
    
      // Additional initialization code here
    };

If you encounter any issues that are Facebook-related, a good resource is the official getting started guide from Facebook.

There are two main ways to use Facebook with your Parse users: (1) logging in as a Facebook user and creating a Parse.User, or (2) linking Facebook to an existing Parse.User.

Login & Signup

Parse.FacebookUtils provides a way to allow your Parse.Users to log in or sign up through Facebook. This is accomplished using the logIn() method:

Parse.FacebookUtils.logIn(null, {
  success: function(user) {
    if (!user.existed()) {
      alert("User signed up and logged in through Facebook!");
    } else {
      alert("User logged in through Facebook!");
    }
  },
  error: function(user, error) {
    alert("User cancelled the Facebook login or did not fully authorize.");
  }
});

When this code is run, the following happens:

  1. The user is shown the Facebook login dialog.
  2. The user authenticates via Facebook, and your app receives a callback.
  3. Our SDK receives the Facebook data and saves it to a Parse.User. If it's a new user based on the Facebook ID, then that user is created.
  4. Your success callback is called with the user.

You may optionally provide a comma-delimited string that specifies what permissions your app requires from the Facebook user. For example:

Parse.FacebookUtils.logIn("user_likes,email", {
  success: function(user) {
    // Handle successful login
  },
  error: function(user, error) {
    // Handle errors and cancellation
  }
});

Parse.User integration doesn't require any permissions to work out of the box (ie. null or specifying no permissions is perfectly acceptable). Read more about permissions on Facebook's developer guide.

It is up to you to record any data that you need from the Facebook user after they authenticate. To accomplish this, you'll need to do a graph query via Facebook's SDK.

Linking

If you want to associate an existing Parse.User to a Facebook account, you can link it like so:

if (!Parse.FacebookUtils.isLinked(user)) {
  Parse.FacebookUtils.link(user, null, {
    success: function(user) {
      alert("Woohoo, user logged in with Facebook!");
    },
    error: function(user, error) {
      alert("User cancelled the Facebook login or did not fully authorize.");
    }
  });
}

The steps that happen when linking are very similar to log in. The difference is that on successful login, the existing Pars.eUser is updated with the Facebook information. Future logins via Facebook will now log the user into their existing account.

If you want to unlink Facebook from a user, simply do this:

Parse.FacebookUtils.unlink(user, {
  success: function(user) {
    alert("The user is no longer associated with their Facebook account.");
  }
});

Facebook SDK and Parse

The Facebook Javascript SDK provides a main FB object that is the starting point for many of the interactions with Facebook's API. You can read more about their SDK here.

Facebook login using the Parse SDK requires that the Facebook SDK already be loaded before calling Parse.FacebookUtils.init().

Our library manages the FB object for you. The FB singleton is synchronized with the current user by default, so any methods you call on it will be acting on the Facebook user associated with the current Parse.User. Calling FB.login() or FB.logOut() explicitly will cause the Parse.User and FB object to fall out of synchronization, and is not recommended.

Cloud Functions

Cloud Functions can be called from JavaScript using Parse.Cloud.run. For example, to call the Cloud Function named hello:

Parse.Cloud.run('hello', {}, {
  success: function(result) {
    // result is 'Hello world!'
  },
  error: function(error) {
  }
});
Take a look at the Cloud Code Guide to learn more about Cloud Functions.

GeoPoints

Parse allows you to associate real-world latitude and longitude coordinates with an object. Adding a Parse.GeoPoint to a Parse.Object allows queries to take into account the proximity of an object to a reference point. This allows you to easily do things like find out what user is closest to another user or which places are closest to a user.

Parse.GeoPoint

To associate a point with an object you first need to create a Parse.GeoPoint. For example, to create a point with latitude of 40.0 degrees and -30.0 degrees longitude:

var point = new Parse.GeoPoint({latitude: 40.0, longitude: -30.0});

This point is then stored in the object as a regular field.

placeObject.set("location", point);

Note: Currently only one key in a class may be a Parse.GeoPoint.

Geo Queries

Now that you have a bunch of objects with spatial coordinates, it would be nice to find out which objects are closest to a point. This can be done by adding another restriction to Parse.Query using near. Getting a list of ten places that are closest to a user may look something like:

// User's location
var userGeoPoint = userObject.get("location");
// Create a query for places
var query = new Parse.Query(PlaceObject);
// Interested in locations near user.
query.near("location", userGeoPoint);
// Limit what could be a lot of points.
query.limit(10);
// Final list of objects
query.find({
  success: function(placesObjects) {
  }
});

At this point placesObjects will be an array of objects ordered by distance (nearest to farthest) from userGeoPoint. Note that if an additional ascending()/descending() order-by constraint is applied, it will take precedence over the distance ordering.

To limit the results using distance, check out withinMiles, withinKilometers, and withinRadians.

It's also possible to query for the set of objects that are contained within a particular area. To find the objects in a rectangular bounding box, add the withinGeoBox restriction to your Parse.Query.

var southwestOfSF = new Parse.GeoPoint(37.708813, -122.526398);
var northeastOfSF = new Parse.GeoPoint(37.822802, -122.373962);

var query = new Parse.Query(PizzaPlaceObject);
query.withinGeoBox("location", southwestOfSF, northeastOfSF);
query.find({
  success: function(pizzaPlacesInSF) {
    ...
  }
});

Caveats

At the moment there are a couple of things to watch out for:

  1. Each Parse.Object class may only have one key with a Parse.GeoPoint object.
  2. Points should not equal or exceed the extreme ends of the ranges. Latitude should not be -90.0 or 90.0. Longitude should not be -180.0 or 180.0. Attempting to set latitude or longitude out of bounds will cause an error.

Push Notifications

To learn more about push check out our Push Notification Guide!

Views

We've included Parse.View which is just a copy of Backbone.View. Feel free to use it for constructing views in your app. Take a look at the Backbone.View API for details on how to use this class. Note that once you use Parse.View, you will need to include jQuery or a jQuery compatible $ method.

Converting Backbone Apps

If you already have an existing Backbone application, it's easy to convert it to use our JavaScript SDK. After converting, you'll end up with a collection of static files that contain all your app's functionality.

Read our Todo App with JavaScript tutorial where you will learn how to create the canonical Backbone todo application using Parse as the backend to persist user accounts and data.

Our JavaScript SDK is Backbone compatible, which means that our Parse.Object and Parse.Collection can be dropped in for Backbone.Model and Backbone.Collection with minor tweaks. Here's how to convert your app:

  1. Follow the instructions for installing the SDK for an existing JavaScript app.
  2. Replace all instances of Backbone.Model with Parse.Object. When doing so, url and urlRoot should be replaced with an appropriate className that maps your objects to a Parse class:

    var BackboneTodo = Backbone.Model.extend({
      urlRoot: "/todos"
    });
    
    var ParseTodo = Parse.Object.extend({
      className: "Todo"
    });
  3. Replace all instances of Backbone.Collection with Parse.Collection and specify the Parse.Object class as the model. You should also specify a query so that the collection knows how to fetch the objects:

    var ParseTodoCollection = Parse.Collection.extend({
      model: ParseTodo
    });
    
    var todos = new ParseTodoCollection();
    
    // Construct a query to get the current user's todo items
    var query = new Parse.Query(ParseTodo);
    query.equalTo("user", Parse.User.current());
    todos.query = query;
    todos.fetch();
  4. Anywhere you were constructing models from a server you'll need to construct a Parse.Query to grab the objects that you're interested in, similar to what we had to do for the query attribute on the Parse.Collection.

  5. Add or update your app to use user authentication and apply ACLs as necessary to objects.

And that's it. Your app should be functional and using Parse as the backend.

Error Handling

Most Parse JavaScript functions report their success or failure using an object with callbacks, similar to a Backbone "options" object. The two primary callbacks used are success and error. success is called whenever an operation completes without errors. Generally, its parameter will be either the Parse.Object in the case of save or get, or an array of Parse.Object for find.

error is called for any kind of error that occurs when interacting with the Parse Cloud over the network. These errors are either related to problems connecting to the cloud or problems performing the requested operation. Let's take a look at another example. In the code below, we try to fetch an object with a non-existent objectId. The Parse Cloud will return an error - so here's how to handle it properly in your callback:

var query = new Parse.Query(Note);
query.get("aBcDeFgH", {
  success: function(results) {
    // This function will *not* be called.
    alert("Everything went fine!");
  },
  error: function(model, error) {
    // This will be called.
    // error is an instance of Parse.Error with details about the error.
    if (error.code === Parse.Error.OBJECT_NOT_FOUND) {
      alert("Uh oh, we couldn't find the object!");
    }
  }
});

The query might also fail because the device couldn't connect to the Parse Cloud. Here's the same callback but with a bit of extra code to handle that scenario:

var query = new Parse.Query(Note);
query.get("thisObjectIdDoesntExist", {
  success: function(results) {
    // This function will *not* be called.
    alert("Everything went fine!");
  },
  error: function(model, error) {
    // This will be called.
    // error is an instance of Parse.Error with details about the error.
    if (error.code === Parse.Error.OBJECT_NOT_FOUND) {
      alert("Uh oh, we couldn't find the object!");
    } else if (error.code === Parse.Error.CONNECTION_FAILED) {
      alert("Uh oh, we couldn't even connect to the Parse Cloud!");
    }
  }
});

For methods like save and signUp that affect a particular Parse.Object, the first argument to the error function will be the object itself, and the second will be the Parse.Error object. This is for compatibility with Backbone-type frameworks. For a list of all possible Parse.Error codes, see the Error Codes section of the JavaScript API.