diff --git a/_includes/js/geopoints.md b/_includes/js/geopoints.md index 3411abd19..d80b56326 100644 --- a/_includes/js/geopoints.md +++ b/_includes/js/geopoints.md @@ -57,6 +57,38 @@ query.find({ }); +You can query for whether an object lies within or on a polygon of `Parse.GeoPoint` (minimum 3 points): + +

+query.withinPolygon("location", [geoPoint1, geoPoint2, geoPoint3]);
+query.find({
+  success: function(objectsWithGeoPointInPolygon) {
+    ...
+  }
+});
+
+ +You can also query for whether an object `Parse.Polygon` contains a `Parse.GeoPoint`: + +

+const p1 = [[0,0], [0,1], [1,1], [1,0]];
+const p2 = [[0,0], [0,2], [2,2], [2,0]];
+const p3 = [[10,10], [10,15], [15,15], [15,10], [10,10]];
+
+const polygon1 = new Parse.Polygon(p1);
+const polygon2 = new Parse.Polygon(p2);
+const polygon3 = new Parse.Polygon(p3);
+
+const point = new Parse.GeoPoint(0.5, 0.5);
+const query = new Parse.Query(TestObject);
+query.polygonContains('polygon', point);
+query.find({
+  success: function(results) {
+    // objects contains polygon1 and polygon2
+  }
+});
+
+ ## Caveats At the moment there are a couple of things to watch out for: diff --git a/_includes/js/queries.md b/_includes/js/queries.md index 156459b1c..1b203d120 100644 --- a/_includes/js/queries.md +++ b/_includes/js/queries.md @@ -205,6 +205,39 @@ The above example will match any `BarbecueSauce` objects where the value in the Queries that have regular expression constraints are very expensive, especially for classes with over 100,000 records. Parse restricts how many such operations can be run on a particular app at any given time. +### Full Text Search + +You can use `fullText` for efficient search capabilities. Text indexes are automatically created for you. Your strings are turned into tokens for fast searching. + +* Note: Full Text Search can be resource intensive. Ensure the cost of using indexes is worth the benefit, see [storage requirements & performance costs of text indexes.](https://docs.mongodb.com/manual/core/index-text/#storage-requirements-and-performance-costs). + +* Parse Server 2.5.0+ + +

+var query = new Parse.Query(BarbecueSauce);
+query.fullText('name', 'bbq');
+
+ +The above example will match any `BarbecueSauce` objects where the value in the "name" String key contains "bbq". For example, both "Big Daddy's BBQ", "Big Daddy's bbq" and "Big BBQ Daddy" will match. + +

+// You can sort by weight / rank. ascending('') and select()
+var query = new Parse.Query(BarbecueSauce);
+query.fullText('name', 'bbq');
+query.ascending('$score');
+query.select('$score');
+query.find()
+  .then(function(results) {
+    // results contains a weight / rank in result.get('score')
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ + + +For Case or Diacritic Sensitive search, please use the [REST API](http://docs.parseplatform.org/rest/guide/#queries-on-string-values). ## Relational Queries @@ -391,3 +424,153 @@ mainQuery.find() // There was an error. }); + +## Aggregate + +Queries can be made using aggregates, allowing you to retrieve objects over a set of input values. The results will not be `Parse.Object`s since you will be aggregating your own fields + +* Parse Server 2.7.1+ +* `MasterKey` is Required. + +Aggregates use stages to filter results by piping results from one stage to the next. + +You can create a pipeline using an Array or an Object. + +The following example is a pipeline similar to `distinct` grouping by name field. + +

+var pipelineObject = {
+  group: { objectId: '$name' }
+ };
+
+var pipelineArray = [
+  { group: { objectId: '$name' } }
+];
+
+ +For a list of available operators please refer to [Mongo Aggregate Documentation](https://docs.mongodb.com/v3.2/reference/operator/aggregation/). + +* Note: Most operations in Mongo Aggregate Documentation will work with Parse Server, but `_id` doesn't exist. Please replace with `objectId`. + +Group pipeline is similar to `distinct`. + +You can group by a field. + +

+// score is the field. $ before score lets the database know this is a field
+var pipeline = [
+  group: { objectId: '$score' }
+];
+var query = new Parse.Query("User");
+query.aggregate(pipeline);
+query.find()
+  .then(function(results) {
+    // results contains unique score values
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +You can apply collective calculations like $sum, $avg, $max, $min. + +

+// total will be a newly created field to hold the sum of score field
+var pipeline = [
+  group: { objectId: null, total: { $sum: '$score' } }
+];
+var query = new Parse.Query("User");
+query.aggregate(pipeline);
+query.find()
+  .then(function(results) {
+    // results contains sum of score field and stores it in results[0].total
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +Project pipeline is similar to `keys` or `select`, add or remove existing fields. + +

+var pipeline = [
+  project: { name: 1 }
+];
+var query = new Parse.Query("User");
+query.aggregate(pipeline);
+query.find()
+  .then(function(results) {
+    // results contains only name field
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +Match pipeline is similar to `equalTo`. + +

+var pipeline = [
+  { match: { name: 'BBQ' } }
+];
+var query = new Parse.Query("User");
+query.aggregate(pipeline);
+query.find()
+  .then(function(results) {
+    // results contains name that matches 'BBQ'
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +You can match by comparison. + +

+var pipeline = [
+  match: { score: { $gt: 15 } }
+];
+var query = new Parse.Query("User");
+query.aggregate(pipeline);
+query.find()
+  .then(function(results) {
+    // results contains score greater than 15
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +## Distinct + +Queries can be made using distinct, allowing you find unique values for a specified field. + +* Parse Server 2.7.1+ +* `MasterKey` is required. + +

+var query = new Parse.Query("User");
+query.distinct("age");
+query.find()
+  .then(function(results) {
+    // results contains unique age
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
+ +You can also restrict results by using `equalTo`. + +

+var query = new Parse.Query("User");
+query.equalTo("name", "foo");
+query.distinct("age");
+query.find()
+  .then(function(results) {
+    // results contains unique age where name is foo
+  })
+  .catch(function(error) {
+    // There was an error.
+  });
+
diff --git a/_includes/js/schema.md b/_includes/js/schema.md new file mode 100644 index 000000000..87105375f --- /dev/null +++ b/_includes/js/schema.md @@ -0,0 +1,147 @@ +# Schema + +Schema is the structure representing classes in your app. You can use the schema +of an app to verify operations in a unit test, generate test data, generate test +classes and then clean up after tests. The schema API can also be used to create +custom views of your data. We use the schema API to display column names and +types in the databrowser. + +This API allows you to access the schemas of your app. + +* Parse Server 2.7.1+ +* `MasterKey` is required. + +Schema will return an object similar to the following: + +

+{
+  className: 'MyClass',
+  fields: {
+    // Default fields
+    ACL: {type: 'ACL'},
+    createdAt: {type: 'Date'},
+    updatedAt: {type: 'Date'},
+    objectId: {type: 'String'},
+    // Custom fields
+    aNumber: {type: 'Number'},
+    aString: {type: 'String'},
+    aBool: {type: 'Boolean'},
+    aDate: {type: 'Date'},
+    aObject: {type: 'Object'},
+    aArray: {type: 'Array'},
+    aGeoPoint: {type: 'GeoPoint'},
+    aPolygon: {type: 'Polygon'},
+    aFile: {type: 'File'}
+  },
+  classLevelPermissions: {
+    find: {
+      '*': true
+    },
+    create: {
+      '*': true
+    },
+    get: {
+      '*': true
+    },
+    update: {
+      '*': true
+    },
+    addField: {
+      '*': true
+    },
+    delete: {
+      '*': true
+    }
+  },
+  indexes: {
+    indexName: { aString: 1 },
+  }
+}
+
+ +Direct manipulation of the classes that are on your server is possible through ParseSchema. Although fields and classes can be automatically generated (the latter assuming client class creation is enabled) ParseSchema gives you explicit control over these classes and their fields. + +*With great power comes great responsibility. Altering the schema directly should be done with care, you can't go back to retrieve data if you remove a field and it's associated values.* + +

+// create an instance to manage your class
+const mySchema = new Parse.Schema('MyClass');
+
+// gets the current schema data
+mySchema.get();
+
+// returns schema for all classes
+Parse.Schema.all()
+
+// add any # of fields, without having to create any objects
+mySchema
+  .addString('stringField')
+  .addNumber('numberField')
+  .addBoolean('booleanField')
+  .addDate('dateField')
+  .addFile('fileField')
+  .addGeoPoint('geoPointField')
+  .addPolygon('polygonField')
+  .addArray('arrayField')
+  .addObject('objectField')
+  .addPointer('pointerField', '_User')
+  .addRelation('relationField', '_User');
+
+// new types can be added as they are available
+mySchema.addField('newField', 'ANewDataType')
+
+// save/update this schema to persist your field changes
+mySchema.save().then((result) => {
+  // returns save new schema
+});
+// or
+mySchema.update().then((result) => {
+  // updates existing schema
+});
+
+ +Assuming you want to remove a field you can simply call `deleteField` and `save/update` to clear it out. + +

+mySchema.deleteField('stringField');
+mySchema.save();
+// or for an existing schema...
+mySchema.update();
+
+ +## Indexes + +Indexes support efficient execution of queries from the database. Keep in mind that the `masterKey` is required for these operations, so be sure it's set in your initialization code before you use this feature. + +

+// To add an index, the field must exist before you create an index
+mySchema.addString('stringField');
+const index = {
+  stringField: 1
+};
+mySchema.addIndex('stringFieldIndex', index);
+mySchema.save().then((result) => {
+  // returns schema including index stringFieldIndex and field stringField
+});
+
+// Delete an index
+testSchema.deleteIndex('indexName');
+mySchema.save().then((result) => {
+  // returns schema without indexName index
+});
+
+// If indexes exist, you can retrieve them
+mySchema.get().then((result) => {
+  // result.indexes
+});
+
+ +## Purge + +All objects can be purged from a schema (class) via purge. But *be careful*! This can be considered an irreversible action. Only do this if you really need to delete all objects from a class, such as when you need to delete the class (as in the code example above). + +

+// delete all objects in the schema
+mySchema.purge();
+
+ diff --git a/_includes/rest/schemas.md b/_includes/rest/schemas.md index 72cce1e5d..9305e9e13 100644 --- a/_includes/rest/schemas.md +++ b/_includes/rest/schemas.md @@ -9,7 +9,7 @@ types in the databrowser. This API allows you to access the schemas of your app. Note: This API can be only accessed using the `master key`. -* Starting with Parse-Server 3.0 Index support added. +* Starting with Parse Server 2.7.1 Index support added. ## Fetch the schema To fetch the Schema for all the classes of your app, run: diff --git a/js.md b/js.md index 5c69094d7..289d5e253 100644 --- a/js.md +++ b/js.md @@ -22,6 +22,7 @@ sections: - "js/analytics.md" - "common/data.md" - "common/relations.md" +- "js/schema.md" - "js/handling-errors.md" - "common/security.md" - "common/performance.md"