From b8bb023c31d3d7d8b473973b6734b476bc8c74bd Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sun, 13 Feb 2022 19:35:26 +0100 Subject: [PATCH 1/3] feat: defined schema docs --- .../defined-schema/class-level-permissions.md | 59 +++++++++ .../defined-schema/core-classes-fields.md | 108 ++++++++++++++++ _includes/defined-schema/fields.md | 34 +++++ _includes/defined-schema/getting-started.md | 122 ++++++++++++++++++ _includes/defined-schema/indexes.md | 26 ++++ _includes/defined-schema/options.md | 39 ++++++ defined-schema.md | 19 +++ index.md | 3 +- 8 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 _includes/defined-schema/class-level-permissions.md create mode 100644 _includes/defined-schema/core-classes-fields.md create mode 100644 _includes/defined-schema/fields.md create mode 100644 _includes/defined-schema/getting-started.md create mode 100644 _includes/defined-schema/indexes.md create mode 100644 _includes/defined-schema/options.md create mode 100644 defined-schema.md diff --git a/_includes/defined-schema/class-level-permissions.md b/_includes/defined-schema/class-level-permissions.md new file mode 100644 index 000000000..a78453c50 --- /dev/null +++ b/_includes/defined-schema/class-level-permissions.md @@ -0,0 +1,59 @@ +# Class Level Permissions + +Setting Class level permissions through Defined Schema is a good first step into security systems available on Parse Server. + +## CLP Keys + +These CLP keys are available: + +- `find`: Control search permissions +- `get`: Control direct ID get permission +- `count`: Control counting objects permission +- `create`: Create permission +- `update`: Update permission +- `delete`: Delete permission +- `protectedFields`: Control get permission at field level + +You can set each CLP field with options to add a first strong security layer. This security layer will be applied on the Parse Class and all Parse Objects into this class. + +Note: If you update CLP you do not need to update Parse Objects. CLP is a security layer at Class Level not Object Level. For Object Level permission you can take a look to ALCs. You can use CLPs combined to ACLs to deeply secure your Parse Server. + +## CLP Key Options + +Available options for CLP keys: + +- `role:MyRole`: If you have already created a Parse Role, you can use your created Parse Role (ie: `MyRole`) in CLP keys. +- `requiresAuthentication`: If true an authenticated user will have the permission. +- `*`: Everybody has the permission +- `{}`: if you set the CLP key with `{}` like `create: {}` only calls with your Parse Server Master Key will have the permission + +## CLP Protected Fields Key + +This CLP key is powerful and need some additional explanation. +We will take the Parse User class as example. + +```js +{ + protectedFields: { + "*": ["authData", "emailVerified", "password", "username"], + }, +} +``` + +Listed keys under `*` will be protected from all users. Don't worry by default, `authData`, `emailVerified`, `password` are protected. +But here for example we protect `username` from all users. So user A, even authenticated will not be able to get the `username` of a user B. + +But protected fields could be combined for example. + +```js +{ + protectedFields: { + "*": ["authData", "emailVerified", "password", "username", "phone", "score"], + "role:Admin": ["password", "authData", "emailVerified"], + "role:VerifiedUser": ["password", "authData", "emailVerified", "score"], + }, +} +``` + +In this case, a user member of the Parse Role `Admin` will be able to get the `phone` and `score` of another User. A user member of the Parse Role `VerifiedUser` can only get `phone`. +If a user is member of `VerifiedUser` and `Admin`, he will have access to `phone` and `score`. diff --git a/_includes/defined-schema/core-classes-fields.md b/_includes/defined-schema/core-classes-fields.md new file mode 100644 index 000000000..8164086e6 --- /dev/null +++ b/_includes/defined-schema/core-classes-fields.md @@ -0,0 +1,108 @@ +# Core Classes/Fields + +Parse will never delete these fields on **ALL** classes if not provided in a class schema + +- `objectId` +- `createdAt` +- `updatedAt` +- `ACL` + +Parse will never delete these classes/fields if not provided in `schema` option. + +- `_User` + + - `username` + - `password` + - `email` + - `emailVerified` + - `authData` + +- `_Installation` + + - `installationId` + - `deviceToken` + - `channels` + - `deviceType` + - `pushType` + - `GCMSenderId` + - `timeZone` + - `localeIdentifier` + - `badge` + - `appVersion` + - `appName` + - `appIdentifier` + - `parseVersion` + +- `_Role` + + - `name` + - `users` + - `roles` + +- `_Session` + + - `user` + - `installationId` + - `sessionToken` + - `expiresAt` + - `createdWith` + +- `_Product` + + - `productIdentifier` + - `download` + - `downloadName` + - `icon` + - `order` + - `title` + - `subtitle` + +- `_PushStatus` + + - `pushTime` + - `source` + - `query` + - `payload` + - `title` + - `expiry` + - `expiration_interval` + - `status` + - `numSent` + - `numFailed` + - `pushHash` + - `errorMessage` + - `sentPerType` + - `failedPerType` + - `sentPerUTCOffset` + - `failedPerUTCOffset` + - `count` + +- `_JobStatus` + + - `jobName` + - `source` + - `status` + - `message` + - `params` + - `finishedAt` + +- `_JobSchedule` + + - `jobName` + - `description` + - `params` + - `startAfter` + - `daysOfWeek` + - `timeOfDay` + - `lastRun` + - `repeatMinutes` + +- `_Audience` + - `objectId` + - `name` + - `query` + - `lastUsed` + - `timesUsed` +- `_Idempotency` + - `reqId` + - `expire` diff --git a/_includes/defined-schema/fields.md b/_includes/defined-schema/fields.md new file mode 100644 index 000000000..12394d6d1 --- /dev/null +++ b/_includes/defined-schema/fields.md @@ -0,0 +1,34 @@ +# Fields + +You can find here all field types available on Parse + +- `Number`: this type support `required` and `defaultValue` +- `String`: this type support `required` and `defaultValue` +- `Boolean`: this type support `required` and `defaultValue` +- `Date`: this type support `required` and `defaultValue` +- `Object`: this type support `required` and `defaultValue` +- `Array`: this type support `required` and `defaultValue` +- `GeoPoint`: this type support `required` +- `File`: this type support `required` +- `Bytes`: this type support `required` +- `Polygon`: this type support `required` +- `Relation`: You need to provide `targetClass` +- `Pointer`: You need to provide `targetClass`, this type support `required` + +Example: + +```js +const UserSchema = { + className: "_User", + fields: { + birthDate: { type: "Date" }, + firstname: { type: "String", required: true }, + lastname: { type: "String", required: true }, + tags: { type: "Array" }, + location: { type: "GeoPoint" }, + city: { type: "Pointer", targetClass: "City" }, + friends: { type: "Relation", targetClass: "_User" }, + zone: { type: "Polygon" }, + }, +}; +``` diff --git a/_includes/defined-schema/getting-started.md b/_includes/defined-schema/getting-started.md new file mode 100644 index 000000000..217015f02 --- /dev/null +++ b/_includes/defined-schema/getting-started.md @@ -0,0 +1,122 @@ +# Getting Started + +## Introduction + +Parse Server was historically designed to be a schema less system. You didn't have to perform migration and define specific database schemas at start up time. +But schema less do not fulfill each use case of developers and could also do not play very well with some new Parse Server features like the GraphQL API. + +To meet these needs, Parse Server now introduce Defined Schemas feature. +Define easily you Parse Classes fields, indexes, Class level permissions and more. + +## Quick Start + +To leverage the power of Defined Schema we recommend to setup parse user like an express app. + +```js +const { ParseServer } = require("parse-server"); + +const UserSchema = { + className: "_User", + fields: { + birthDate: { type: "Date" }, + firstname: { type: "String", required: true }, + lastname: { type: "String", required: true }, + tags: { type: "Array" }, + location: { type: "GeoPoint" }, + city: { type: "Pointer", targetClass: "City" }, + friends: { type: "Relation", targetClass: "_User" }, + zone: { type: "Polygon" }, + }, + indexes: { + tagsIndex: { tags: 1 }, + // Special _p_ word to create indexes on pointer fields + cityPointerIndex: { _p_city: 1 }, + tagAndCityIndex: { _p_city: 1, tags: 1 }, + }, + classLevelPermissions: { + find: { requiresAuthentication: true }, + count: { "role:Admin": true }, + get: { requiresAuthentication: true }, + update: { requiresAuthentication: true }, + create: { "role:Admin": true }, + delete: { "role:Admin": true }, + protectedFields: { + // These fields will be protected from all other users + // authData, and password are already protected by default + "*": ["authData", "emailVerified", "password", "username"], + }, + }, +}; + +const City = { + className: "City", + fields: { + name: { type: "String", required: true }, + location: { type: "GeoPoint" }, + country: { type: "Pointer", targetClass: "Country" }, + }, + classLevelPermissions: { + find: { requiresAuthentication: true }, + count: { requiresAuthentication: true }, + get: { requiresAuthentication: true }, + // Only a user linked into the Admin Parse Role + // authorized to manage cities + update: { "role:Admin": true }, + create: { "role:Admin": true }, + delete: { "role:Admin": true }, + }, +}; + +const Country = { + className: "Country", + fields: { + name: { type: "String", required: true }, + }, + classLevelPermissions: { + find: { requiresAuthentication: true }, + count: { requiresAuthentication: true }, + get: { requiresAuthentication: true }, + // Empty object meas that only master key + // is authorized to manage countries + update: {}, + create: {}, + delete: {}, + }, +}; + +ParseServer.start({ + databaseURI: "mongodb://your.mongo.uri", + appId: "myAppId", + masterKey: "mySecretMasterKey", + serverURL: "http://localhost:1337/parse", + port: 1337, + publicServerURL: "http://localhost:1337/parse", + // Then just register schemas into Parse Server + schema: { + definitions: [User, City, Country], + // Parse Schema API will be disabled + // If you need to update schemas Parse server + // need to be updated and deployed (CI/CD strategy) + lockSchemas: true, + // If true, Parse Server will delete non defined Classes from + // the database. (Core classes like Role, User are never deleted) + strict: true, + // If true, a field type change, the changed field is deleted + // from the database (all data in this field will be deleted) + // and then create the field with the new type + recreateModifiedFields: true, + // If true, Parse will delete non defined fields on a class. (Core fields are never deleted) + deleteExtraFields: true, + }, + serverStartComplete: () => { + // Here your Parse Server is ready + // with schemas up to date + + // Just a code example if you want to expose + // an endpoint when parse is fully initialized + parseServer.expressApp.get("/ready", (req: any, res: any) => { + res.send("true"); + }); + }, +}); +``` diff --git a/_includes/defined-schema/indexes.md b/_includes/defined-schema/indexes.md new file mode 100644 index 000000000..78af5dc36 --- /dev/null +++ b/_includes/defined-schema/indexes.md @@ -0,0 +1,26 @@ +# Indexes + +To optimize you Parse Server database performance you can define indexes and compound indexes. + +To define an index on a `Pointer` field you need to use a +special notation `_p_myFieldName`. +For example if you define `city: { type: "Pointer", targetClass: "City" }` in your `fields` you can define an index on this pointer with `cityIndexExample: { _p_city: true }` + +Note: Currently Defined Schemas do not support indexes on special `_Join` classes used under the hood by the `Relation` type + +Example: + +```js +const UserSchema = { + className: "_User", + fields: { + tags: { type: "Array" }, + city: { type: "Pointer", targetClass: "City" }, + }, + indexes: { + tagsIndex: { tags: 1 }, + cityPointerIndex: { _p_city: 1 }, + tagAndCityIndex: { _p_city: 1, tags: 1 }, + }, +}; +``` diff --git a/_includes/defined-schema/options.md b/_includes/defined-schema/options.md new file mode 100644 index 000000000..13e9bd842 --- /dev/null +++ b/_includes/defined-schema/options.md @@ -0,0 +1,39 @@ +# Options + +## definitions + +You classes definitions stored in an `Array`. + +## strict + +You can set the `strict` option to `true` if you want parse-server to delete removed classes from your schemas from your database. Data stored in removed classes will be lost. + +`strict` is default to `false`. If you often change your schemas be aware that you can have some stale classes in your database. You will need to delete these classes manually. + +## deleteExtraFields + +You can set the `deleteExtraFields` option to `true` if you parse-server to delete removed a class field from your database. Data stored in the removed field will be lost. + +`deleteExtraFields` is default to `false`. Be aware that some stale fields could exists in your database. You will need to delete these fields manually. + +## recreateModifiedFields + +You can set the `recreateModifiedFields` option to `true` if you parse-server to clean field data before parse-server update the field type when you change the type of a field (ie: from `String` to `Number`). Data stored on the modified field will be lost. + +`recreateModifiedFields` is default to `false`. Be aware that if you do not perform some data migration, you can result with data type inconsistency on modified field. + +On production a good practice could be to create a new field with your new type, and then create a Parse Cloud Job to migrate old field data to the new created field. + +## lockSchemas + +You can set the `lockSchemas` option to `true` if you want to to prevent any `Parse.Schema` manipulation outside of the Defined Schema feature. If this options is `true` any create/update/delete request to `Parse.Schema` will be denied. You will not be able to manipulate `indexes`, `classLevelPermissions`, `fields`. + +This option help to keep one source of truth. And prevent developers or custom code to interfere with your schema definitions and data structure, even with the master key. + +## beforeMigration + +A function called before parse-server performs schema updates based on the `definitions` option + +## afterMigration + +A function called after parse-server performed schema updates based on the `definitions` option diff --git a/defined-schema.md b/defined-schema.md new file mode 100644 index 000000000..dec0e5e5f --- /dev/null +++ b/defined-schema.md @@ -0,0 +1,19 @@ +--- +title: Defined Schema Guide | Parse +permalink: /defined-schema/guide/ +layout: guide +platform: cloudcode +language: js +display_platform: Defined Schema + +redirect_from: + - /defined-schema/ + +sections: + - "defined-schema/getting-started.md" + - "defined-schema/core-classes-fields.md" + - "defined-schema/fields.md" + - "defined-schema/indexes.md" + - "defined-schema/class-level-permissions.md" + - "defined-schema/options.md" +--- diff --git a/index.md b/index.md index 48d94d536..2424ba37b 100644 --- a/index.md +++ b/index.md @@ -2,7 +2,6 @@ title: Docs | Parse permalink: index.html layout: docs - ---
@@ -171,7 +170,7 @@ layout: docs
From 2b651bbfd105ff424211fd80f288bad01e1c62b5 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Sat, 5 Mar 2022 10:35:38 +0100 Subject: [PATCH 2/3] fix: requested changes --- .../defined-schema/class-level-permissions.md | 30 ++++++++-------- .../defined-schema/core-classes-fields.md | 2 +- _includes/defined-schema/fields.md | 34 ++++++++++++------- _includes/defined-schema/getting-started.md | 12 +++---- _includes/defined-schema/indexes.md | 8 ++--- _includes/defined-schema/options.md | 12 +++---- 6 files changed, 52 insertions(+), 46 deletions(-) diff --git a/_includes/defined-schema/class-level-permissions.md b/_includes/defined-schema/class-level-permissions.md index a78453c50..537eeed42 100644 --- a/_includes/defined-schema/class-level-permissions.md +++ b/_includes/defined-schema/class-level-permissions.md @@ -1,10 +1,10 @@ # Class Level Permissions -Setting Class level permissions through Defined Schema is a good first step into security systems available on Parse Server. +Setting Class Level Permissions through Defined Schema is a good first step into security systems available on Parse Server. -## CLP Keys +## CLP Parameters -These CLP keys are available: +These CLP parameters are available: - `find`: Control search permissions - `get`: Control direct ID get permission @@ -14,25 +14,27 @@ These CLP keys are available: - `delete`: Delete permission - `protectedFields`: Control get permission at field level -You can set each CLP field with options to add a first strong security layer. This security layer will be applied on the Parse Class and all Parse Objects into this class. +You can set each CLP parameter to add a first strong security layer. This security layer will be applied on the Parse Class and will cover all Parse Objects of the Parse Class. Note: If you update CLP you do not need to update Parse Objects. CLP is a security layer at Class Level not Object Level. For Object Level permission you can take a look to ALCs. You can use CLPs combined to ACLs to deeply secure your Parse Server. -## CLP Key Options +## CLP Parameter Options -Available options for CLP keys: +Available options for CLP parameters: - `role:MyRole`: If you have already created a Parse Role, you can use your created Parse Role (ie: `MyRole`) in CLP keys. - `requiresAuthentication`: If true an authenticated user will have the permission. - `*`: Everybody has the permission - `{}`: if you set the CLP key with `{}` like `create: {}` only calls with your Parse Server Master Key will have the permission -## CLP Protected Fields Key +## CLP Protected Fields Parameter -This CLP key is powerful and need some additional explanation. -We will take the Parse User class as example. +This CLP parameter allows you to restrict access to fields to specific Parse users. + +We will take the Parse User Class as example. ```js +// className: '_User' { protectedFields: { "*": ["authData", "emailVerified", "password", "username"], @@ -40,10 +42,10 @@ We will take the Parse User class as example. } ``` -Listed keys under `*` will be protected from all users. Don't worry by default, `authData`, `emailVerified`, `password` are protected. -But here for example we protect `username` from all users. So user A, even authenticated will not be able to get the `username` of a user B. +Listed keys under `*` will be protected from all users. By default, `authData`, `emailVerified`, `password` are protected. +But in the above example we protect `username` from all users. So a Parse User, even authenticated will not be able to get the `username` of a another Parse User. -But protected fields could be combined for example. +`protectedFields` could be also combined as in the following example. ```js { @@ -55,5 +57,5 @@ But protected fields could be combined for example. } ``` -In this case, a user member of the Parse Role `Admin` will be able to get the `phone` and `score` of another User. A user member of the Parse Role `VerifiedUser` can only get `phone`. -If a user is member of `VerifiedUser` and `Admin`, he will have access to `phone` and `score`. +In the example above, a Parse User member of the Parse Role `Admin` will be able to get the `phone` and `score` of another Parse User. A Parse User member of the Parse Role `VerifiedUser` can only get `phone`. +If a Parse User is member of `VerifiedUser` and `Admin`, he will have access to `phone` and `score`. diff --git a/_includes/defined-schema/core-classes-fields.md b/_includes/defined-schema/core-classes-fields.md index 8164086e6..6c310206d 100644 --- a/_includes/defined-schema/core-classes-fields.md +++ b/_includes/defined-schema/core-classes-fields.md @@ -7,7 +7,7 @@ Parse will never delete these fields on **ALL** classes if not provided in a cla - `updatedAt` - `ACL` -Parse will never delete these classes/fields if not provided in `schema` option. +Parse Server will never delete the following fields from any class, even if these fields are not defined in a class schema. - `_User` diff --git a/_includes/defined-schema/fields.md b/_includes/defined-schema/fields.md index 12394d6d1..2d0c03340 100644 --- a/_includes/defined-schema/fields.md +++ b/_includes/defined-schema/fields.md @@ -1,19 +1,27 @@ # Fields -You can find here all field types available on Parse +These field types are available on a Parse Schema. -- `Number`: this type support `required` and `defaultValue` -- `String`: this type support `required` and `defaultValue` -- `Boolean`: this type support `required` and `defaultValue` -- `Date`: this type support `required` and `defaultValue` -- `Object`: this type support `required` and `defaultValue` -- `Array`: this type support `required` and `defaultValue` -- `GeoPoint`: this type support `required` -- `File`: this type support `required` -- `Bytes`: this type support `required` -- `Polygon`: this type support `required` -- `Relation`: You need to provide `targetClass` -- `Pointer`: You need to provide `targetClass`, this type support `required` +`required`: `boolean`, by default false. Force the field to be set on create and update. +`defaultValue`: `any`, a value used by Parse Server when you create a Parse Object if the field is not provided. +`targetClass`: `string`, a Parse Class name used by Parse Server to validate the `Pointer`/`Relation` + +✅: Supported +❌: Not Supported + +| Type | -- required -- | -- defaultValue -- | -- targetClass -- | +| -------- | -------------- | ------------------ | ----------------- | +| String | ✅ | ✅ | ❌ | +| Boolean | ✅ | ✅ | ❌ | +| Date | ✅ | ✅ | ❌ | +| Object | ✅ | ✅ | ❌ | +| Array | ✅ | ✅ | ❌ | +| GeoPoint | ✅ | ✅ | ❌ | +| File | ✅ | ✅ | ❌ | +| Bytes | ✅ | ✅ | ❌ | +| Polygon | ✅ | ✅ | ❌ | +| Relation | ❌ | ❌ | ✅ (required) | +| Pointer | ✅ | ❌ | ✅ (required) | Example: diff --git a/_includes/defined-schema/getting-started.md b/_includes/defined-schema/getting-started.md index 217015f02..4ff9642d1 100644 --- a/_includes/defined-schema/getting-started.md +++ b/_includes/defined-schema/getting-started.md @@ -2,15 +2,11 @@ ## Introduction -Parse Server was historically designed to be a schema less system. You didn't have to perform migration and define specific database schemas at start up time. -But schema less do not fulfill each use case of developers and could also do not play very well with some new Parse Server features like the GraphQL API. - -To meet these needs, Parse Server now introduce Defined Schemas feature. -Define easily you Parse Classes fields, indexes, Class level permissions and more. +For use cases in which a pre-defined schema is beneficial or required, you can define class fields, indexes, Class Level Permissions and more ## Quick Start -To leverage the power of Defined Schema we recommend to setup parse user like an express app. +You can use Defined Schema as in the following example. ```js const { ParseServer } = require("parse-server"); @@ -104,9 +100,9 @@ ParseServer.start({ // If true, a field type change, the changed field is deleted // from the database (all data in this field will be deleted) // and then create the field with the new type - recreateModifiedFields: true, + recreateModifiedFields: false, // If true, Parse will delete non defined fields on a class. (Core fields are never deleted) - deleteExtraFields: true, + deleteExtraFields: false, }, serverStartComplete: () => { // Here your Parse Server is ready diff --git a/_includes/defined-schema/indexes.md b/_includes/defined-schema/indexes.md index 78af5dc36..06124bd1d 100644 --- a/_includes/defined-schema/indexes.md +++ b/_includes/defined-schema/indexes.md @@ -1,12 +1,12 @@ # Indexes -To optimize you Parse Server database performance you can define indexes and compound indexes. +To optimize the Parse Server performance you can define indexes and compound indexes. To define an index on a `Pointer` field you need to use a -special notation `_p_myFieldName`. -For example if you define `city: { type: "Pointer", targetClass: "City" }` in your `fields` you can define an index on this pointer with `cityIndexExample: { _p_city: true }` +special notation `_p_`. +For example if you define `city: { type: "Pointer", targetClass: "City" }` in your `fields` you can define an index on this pointer with `cityIndexExample: { _p_city: true }`. -Note: Currently Defined Schemas do not support indexes on special `_Join` classes used under the hood by the `Relation` type +Note: Currently Defined Schemas do not support indexes on special `_Join` classes used under the hood by the `Relation` type. Example: diff --git a/_includes/defined-schema/options.md b/_includes/defined-schema/options.md index 13e9bd842..b55e49aa0 100644 --- a/_includes/defined-schema/options.md +++ b/_includes/defined-schema/options.md @@ -2,23 +2,23 @@ ## definitions -You classes definitions stored in an `Array`. +An array of your Defined Parse Classes. ## strict -You can set the `strict` option to `true` if you want parse-server to delete removed classes from your schemas from your database. Data stored in removed classes will be lost. +You can set the `strict` option to `true` if you want Parse Server to delete all Parse Objects when you remove a Defined Parse Class from your `definitions`. Data stored in removed classes will be lost. -`strict` is default to `false`. If you often change your schemas be aware that you can have some stale classes in your database. You will need to delete these classes manually. +`strict` is default to `false`. If you often change your schemas be aware that you will have stale data classes in your database. You will need to delete these classes (collection for MongoDB, table for Postgres) manually, through your database CLI/UI. ## deleteExtraFields -You can set the `deleteExtraFields` option to `true` if you parse-server to delete removed a class field from your database. Data stored in the removed field will be lost. +You can set the `deleteExtraFields` option to `true` if you want Parse Server to delete a removed Defined Parse Class field from your database. Data stored in the removed field will be lost. -`deleteExtraFields` is default to `false`. Be aware that some stale fields could exists in your database. You will need to delete these fields manually. +`deleteExtraFields` is default to `false`. Be aware that you will have stale data fields in your database since Parse Server will not delete field data automatically. You will need to delete these fields manually. ## recreateModifiedFields -You can set the `recreateModifiedFields` option to `true` if you parse-server to clean field data before parse-server update the field type when you change the type of a field (ie: from `String` to `Number`). Data stored on the modified field will be lost. +You can set the `recreateModifiedFields` option to `true` if you want Parse Server to clean field data before Parse Server update the field type when you change the type of a field (ie: from `String` to `Number`). Data stored on the modified field will be lost. `recreateModifiedFields` is default to `false`. Be aware that if you do not perform some data migration, you can result with data type inconsistency on modified field. From 938474c05796a8ee2f157010090870935c72fab8 Mon Sep 17 00:00:00 2001 From: Antoine Cormouls Date: Fri, 18 Mar 2022 11:25:22 +0100 Subject: [PATCH 3/3] fix: add bold --- _includes/defined-schema/options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/defined-schema/options.md b/_includes/defined-schema/options.md index b55e49aa0..8b1dfef28 100644 --- a/_includes/defined-schema/options.md +++ b/_includes/defined-schema/options.md @@ -20,7 +20,7 @@ You can set the `deleteExtraFields` option to `true` if you want Parse Server to You can set the `recreateModifiedFields` option to `true` if you want Parse Server to clean field data before Parse Server update the field type when you change the type of a field (ie: from `String` to `Number`). Data stored on the modified field will be lost. -`recreateModifiedFields` is default to `false`. Be aware that if you do not perform some data migration, you can result with data type inconsistency on modified field. +`recreateModifiedFields` is default to `false`. **Be aware that if you do not perform some data migration, you can result with data type inconsistency on modified field.** On production a good practice could be to create a new field with your new type, and then create a Parse Cloud Job to migrate old field data to the new created field.