{"id":15013317,"url":"https://github.com/meteor-community-packages/meteor-simple-schema","last_synced_at":"2025-05-14T20:04:13.258Z","repository":{"id":9654638,"uuid":"11591669","full_name":"Meteor-Community-Packages/meteor-simple-schema","owner":"Meteor-Community-Packages","description":"Meteor integration package for simpl-schema","archived":false,"fork":false,"pushed_at":"2025-03-28T22:12:50.000Z","size":1666,"stargazers_count":917,"open_issues_count":5,"forks_count":164,"subscribers_count":31,"default_branch":"master","last_synced_at":"2025-04-13T14:04:24.904Z","etag":null,"topics":["cleaning-data","form-generation","form-validation","meteor","meteor-package","meteorjs","schema","validation"],"latest_commit_sha":null,"homepage":"https://github.com/Meteor-Community-Packages/meteor-simple-schema","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Meteor-Community-Packages.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["storytellercz","jankapunkt"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2013-07-22T20:27:27.000Z","updated_at":"2025-03-30T08:57:48.000Z","dependencies_parsed_at":"2024-07-25T13:42:46.510Z","dependency_job_id":"e16270f5-3ed3-4e61-a893-755dc863a240","html_url":"https://github.com/Meteor-Community-Packages/meteor-simple-schema","commit_stats":{"total_commits":358,"total_committers":33,"mean_commits":"10.848484848484848","dds":0.2793296089385475,"last_synced_commit":"cdfe749f428eb62a78b25670ebe282c151b2d1c4"},"previous_names":["aldeed/meteor-simple-schema"],"tags_count":81,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-simple-schema","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-simple-schema/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-simple-schema/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-simple-schema/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Meteor-Community-Packages","download_url":"https://codeload.github.com/Meteor-Community-Packages/meteor-simple-schema/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248724639,"owners_count":21151561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cleaning-data","form-generation","form-validation","meteor","meteor-package","meteorjs","schema","validation"],"created_at":"2024-09-24T19:44:04.878Z","updated_at":"2025-04-13T14:04:31.974Z","avatar_url":"https://github.com/Meteor-Community-Packages.png","language":"JavaScript","funding_links":["https://github.com/sponsors/storytellercz","https://github.com/sponsors/jankapunkt"],"categories":[],"sub_categories":[],"readme":"# Meteor SimpleSchema\n[![Meteor Community Package](https://img.shields.io/badge/Meteor-Package-green?logo=meteor\u0026logoColor=white)](https://meteor.com)\n[![Test suite](https://github.com/Meteor-Community-Packages/meteor-simple-schema/actions/workflows/lint-test-publish.yml/badge.svg)](https://github.com/Meteor-Community-Packages/meteor-simple-schema/actions/workflows/lint-test-publish.yml)\n[![CodeQL](https://github.com/Meteor-Community-Packages/meteor-simple-schema/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Meteor-Community-Packages/meteor-simple-schema/actions/workflows/github-code-scanning/codeql)\n[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)\n![GitHub License](https://img.shields.io/github/license/Meteor-Community-Packages/meteor-simple-schema)\n\n## Attention! 🧐\n\u003e This package is back under maintenance by the Meteor Community Packages group 🚀\n\u003e Consider this a hard-fork to ensure a future-proof maintenance with focus on\n\u003e Meteor-Compatibility (Meteor 2.x; 3.x and beyond)! ☄️\n\n## About this package\nSimpleSchema validates JavaScript objects to ensure they match a schema. It can also clean the objects to automatically convert types, remove unsupported properties, and add automatic values such that the object is then more likely to pass validation.\n\nThere are a lot of similar packages for validating objects. These are some of the features of this package that might be good reasons to choose this one over another:\n\n- Isomorphic. Works on Server and Client\n- The object you validate can be a MongoDB modifier. SimpleSchema understands how to properly validate it such that the object in the database, after undergoing modification, will be valid.\n- Optional `Tracker` reactivity\n- Powerful customizable error message system with decent English language defaults and support for localization, which makes it easy to drop this package in and display the validation error messages to end users.\n- Has hundreds of tests and is used in production apps of various sizes\n- Used by the [Collection2](https://github.com/Meteor-Community-Packages/meteor-collection2) and [AutoForm](https://github.com/Meteor-Community-Packages/meteor-autoform) Meteor packages.\n\nThere are also reasons not to choose this package. Because of all it does, this package is more complex than (but still \"simple\" :) ) and slower than some other packages. Based on your needs, you should decide whether these tradeoffs are acceptable. One faster but less powerful option is [simplecheck](https://www.npmjs.com/package/simplecheck).\n\n## Table of Contents\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [The History of SimpleSchema](#the-history-of-simpleschema)\n- [Installation](#installation)\n- [Lingo](#lingo)\n- [Quick Start](#quick-start)\n  - [Validate an Object and Throw an Error](#validate-an-object-and-throw-an-error)\n  - [Validate an Array of Objects and Throw an Error](#validate-an-array-of-objects-and-throw-an-error)\n  - [Validate a Meteor Method Argument and Satisfy `audit-argument-checks`](#validate-a-meteor-method-argument-and-satisfy-audit-argument-checks)\n  - [Validate an Object and Get the Errors](#validate-an-object-and-get-the-errors)\n  - [Validate a MongoDB Modifier](#validate-a-mongodb-modifier)\n  - [Enable Meteor Tracker Reactivity](#enable-meteor-tracker-reactivity)\n  - [Automatically Clean the Object Before Validating It](#automatically-clean-the-object-before-validating-it)\n  - [Set Default Options for One Schema](#set-default-options-for-one-schema)\n  - [Set Default Options for All Schemas](#set-default-options-for-all-schemas)\n  - [Explicitly Clean an Object](#explicitly-clean-an-object)\n- [Defining a Schema](#defining-a-schema)\n  - [Shorthand Definitions](#shorthand-definitions)\n  - [Longhand Definitions](#longhand-definitions)\n  - [Mixing Shorthand with Longhand](#mixing-shorthand-with-longhand)\n  - [More Shorthand](#more-shorthand)\n  - [Multiple Definitions For One Key](#multiple-definitions-for-one-key)\n  - [Extending Schemas](#extending-schemas)\n    - [Overriding When Extending](#overriding-when-extending)\n  - [Subschemas](#subschemas)\n  - [Extracting Schemas](#extracting-schemas)\n  - [Raw Definition](#raw-definition)\n- [Schema Keys](#schema-keys)\n- [Schema Rules](#schema-rules)\n  - [type](#type)\n  - [label](#label)\n  - [optional](#optional)\n  - [required](#required)\n  - [min/max](#minmax)\n  - [exclusiveMin/exclusiveMax](#exclusiveminexclusivemax)\n  - [minCount/maxCount](#mincountmaxcount)\n  - [allowedValues](#allowedvalues)\n  - [regEx](#regex)\n  - [skipRegExCheckForEmptyStrings](#skipregexcheckforemptystrings)\n  - [blackbox](#blackbox)\n  - [trim](#trim)\n  - [custom](#custom)\n  - [defaultValue](#defaultvalue)\n  - [autoValue](#autovalue)\n    - [autoValue gotchas](#autovalue-gotchas)\n  - [Function Properties](#function-properties)\n  - [Getting field properties](#getting-field-properties)\n- [Validating Data](#validating-data)\n  - [The Object to Validate](#the-object-to-validate)\n  - [Ways to Perform Validation](#ways-to-perform-validation)\n    - [Named Validation Contexts](#named-validation-contexts)\n    - [Unnamed Validation Contexts](#unnamed-validation-contexts)\n  - [Validating an Object](#validating-an-object)\n  - [Validating Only Some Keys in an Object](#validating-only-some-keys-in-an-object)\n  - [Validation Options](#validation-options)\n  - [Validating and Throwing ValidationErrors](#validating-and-throwing-validationerrors)\n    - [Customize the Error That is Thrown](#customize-the-error-that-is-thrown)\n  - [Custom Field Validation](#custom-field-validation)\n  - [Custom Whole-Document Validators](#custom-whole-document-validators)\n  - [Manually Adding a Validation Error](#manually-adding-a-validation-error)\n  - [Asynchronous Custom Validation on the Client](#asynchronous-custom-validation-on-the-client)\n  - [Getting a List of Invalid Keys and Validation Error Messages](#getting-a-list-of-invalid-keys-and-validation-error-messages)\n- [Customizing Validation Messages](#customizing-validation-messages)\n- [Other Validation Context Methods](#other-validation-context-methods)\n- [Other SimpleSchema Methods](#other-simpleschema-methods)\n- [Cleaning Objects](#cleaning-objects)\n- [Dates](#dates)\n- [Best Practice Code Examples](#best-practice-code-examples)\n  - [Make a field conditionally required](#make-a-field-conditionally-required)\n  - [Validate one key against another](#validate-one-key-against-another)\n  - [Translation of Regular Expression Messages](#translation-of-regular-expression-messages)\n- [Debug Mode](#debug-mode)\n- [Extending the Schema Options](#extending-the-schema-options)\n- [Add On Packages](#add-on-packages)\n- [Contributors](#contributors)\n- [License](#license)\n- [Contributing](#contributing)\n  - [Thanks](#thanks)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## The History of SimpleSchema\n\nSimpleSchema was first released as a Meteor package in mid-2013. Version 1.0 was released in September 2014. \nIn mid-2016, new versions were released as an NPM package, which can be used in Meteor, NodeJS, or static browser apps.\nAfterwards it has been archived in favour of the NPM version.\n\nIn 2022/2023 the NPM package has dropped all Meteor compatibility and this package got released again, starting with the latest commit\nthat included full Meteor support.\n\n## Installation\n\n```bash\nmeteor add aldeed:simple-schema\n```\n\n\u003e Make sure, you installed version 2.0.0 or greater!\n\n## Lingo\n\nIn this documentation:\n\n- \"key\", \"field\", and \"property\" generally all mean the same thing: an identifier for some part of an object that is validated by your schema. SimpleSchema uses dot notation to identify nested keys.\n- \"validate\" means to check whether an object matches what you expect, for example, having the expected keys with the expected data types, expected string lengths, etc.\n\n## Quick Start\n\n### Validate an Object and Throw an Error\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nnew SimpleSchema({\n  name: String,\n}).validate({\n  name: 2,\n});\n```\n\n### Validate an Array of Objects and Throw an Error\n\nAn error is thrown for the first invalid object found.\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nnew SimpleSchema({\n  name: String,\n}).validate([{ name: \"Bill\" }, { name: 2 }]);\n```\n\n### Validate a Meteor Method Argument and Satisfy `audit-argument-checks`\n\nTo avoid errors about not checking all arguments when you are using SimpleSchema to validate Meteor method arguments, you must pass `check` as an option when creating your SimpleSchema instance.\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\nimport { check } from \"meteor/check\";\nimport { Meteor } from \"meteor/meteor\";\n\nSimpleSchema.defineValidationErrorTransform((error) =\u003e {\n  const ddpError = new Meteor.Error(error.message);\n  ddpError.error = \"validation-error\";\n  ddpError.details = error.details;\n  return ddpError;\n});\n\nconst myMethodObjArgSchema = new SimpleSchema({ name: String }, { check });\n\nMeteor.methods({\n  myMethod(obj) {\n    myMethodObjArgSchema.validate(obj);\n\n    // Now do other method stuff knowing that obj satisfies the schema\n  },\n});\n```\n\n### Validate an Object and Get the Errors\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst validationContext = new SimpleSchema({\n  name: String,\n}).newContext();\n\nvalidationContext.validate({\n  name: 2,\n});\n\nconsole.log(validationContext.isValid());\nconsole.log(validationContext.validationErrors());\n```\n\n### Validate a MongoDB Modifier\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst validationContext = new SimpleSchema({\n  name: String,\n}).newContext();\n\nvalidationContext.validate(\n  {\n    $set: {\n      name: 2,\n    },\n  },\n  { modifier: true }\n);\n\nconsole.log(validationContext.isValid());\nconsole.log(validationContext.validationErrors());\n```\n\n### Enable Meteor Tracker Reactivity\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\nimport { Tracker } from \"meteor/tracker\";\n\nconst validationContext = new SimpleSchema(\n  {\n    name: String,\n  },\n  { tracker: Tracker }\n).newContext();\n\nTracker.autorun(function () {\n  console.log(validationContext.isValid());\n  console.log(validationContext.validationErrors());\n});\n\nvalidationContext.validate({\n  name: 2,\n});\n\nvalidationContext.validate({\n  name: \"Joe\",\n});\n```\n\nPassing in `Tracker` causes the following functions to become reactive:\n\n- ValidationContext#keyIsInvalid\n- ValidationContext#keyErrorMessage\n- ValidationContext#isValid\n- ValidationContext#validationErrors\n- SimpleSchema#label\n\n### Automatically Clean the Object Before Validating It\n\nTO DO\n\n### Set Default Options for One Schema\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst mySchema = new SimpleSchema(\n  {\n    name: String,\n  },\n  {\n    clean: {\n      autoConvert: true,\n      extendAutoValueContext: {},\n      filter: false,\n      getAutoValues: true,\n      removeEmptyStrings: true,\n      removeNullsFromArrays: false,\n      trimStrings: true,\n    },\n    humanizeAutoLabels: false,\n    requiredByDefault: true,\n  }\n);\n```\n\nThese options will be used every time you clean or validate with this particular SimpleSchema instance.\n\n### Set Default Options for All Schemas\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nSimpleSchema.constructorOptionDefaults({\n  clean: {\n    filter: false,\n  },\n  humanizeAutoLabels: false,\n});\n\n// If you don't pass in any options, it will return the current defaults.\nconsole.log(SimpleSchema.constructorOptionDefaults());\n```\n\nThese options will be used every time you clean or validate with any SimpleSchema instance, but can be overridden by options passed in to the constructor for a single instance.\n\nImportant notes:\n\n- You must call `SimpleSchema.constructorOptionDefaults` before any of your schemas are created, so put it in an entry-point file and/or at the top of your code file.\n- In a large, complex project where SimpleSchema instances might be created by various JavaScript packages, there may be multiple `SimpleSchema` objects. In other words, the `import SimpleSchema` line in one package might be pulling in the `SimpleSchema` object from one package while that line in another package pulls in a completely different `SimpleSchema` object. It will be difficult to know that this is happening unless you notice that your defaults are not being used by some of your schemas. To solve this, you can call `SimpleSchema.constructorOptionDefaults` multiple times or adjust your package dependencies to ensure that only one version of `simpl-schema` is pulled into your project.\n\n### Explicitly Clean an Object\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst mySchema = new SimpleSchema({ name: String });\nconst doc = { name: 123 };\nconst cleanDoc = mySchema.clean(doc);\n// cleanDoc is now mutated to hopefully have a better chance of passing validation\nconsole.log(typeof cleanDoc.name); // string\n```\n\nWorks for a MongoDB modifier, too:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst mySchema = new SimpleSchema({ name: String });\nconst modifier = { $set: { name: 123 } };\nconst cleanModifier = mySchema.clean(modifier);\n// doc is now mutated to hopefully have a better chance of passing validation\nconsole.log(typeof cleanModifier.$set.name); // string\n```\n\n## Defining a Schema\n\nLet's get into some more details about the different syntaxes that are supported when defining a schema. It's probably best to start with the simplest syntax. Here's an example:\n\n### Shorthand Definitions\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  name: String,\n  age: SimpleSchema.Integer,\n  registered: Boolean,\n});\n```\n\nThis is referred to as \"shorthand\" syntax. You simply map a property name to a type. When validating, SimpleSchema will make sure that all of those properties are present and are set to a value of that type.\n\n### Longhand Definitions\n\nIn many cases, you will need to use longhand in order to define additional rules beyond what the data type should be.\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  name: {\n    type: String,\n    max: 40,\n  },\n  age: {\n    type: SimpleSchema.Integer,\n    optional: true,\n  },\n  registered: {\n    type: Boolean,\n    defaultValue: false,\n  },\n});\n```\n\n### Mixing Shorthand with Longhand\n\nYou can use any combination of shorthand and longhand:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  name: String,\n  age: {\n    type: SimpleSchema.Integer,\n    optional: true,\n  },\n  registered: Boolean,\n});\n```\n\n### More Shorthand\n\nIf you set the schema key to a regular expression, then the `type` will be `String` and the string must match the provided regular expression.\n\nFor example, this:\n\n```js\n{\n  exp: /foo/;\n}\n```\n\nis equivalent to:\n\n```js\n{\n  exp: { type: String, regEx: /foo/ }\n}\n```\n\nYou can also set the schema key to an array of some type:\n\n```js\n{\n  friends: [String],\n}\n```\n\nis equivalent to:\n\n```js\n{\n  friends: { type: Array },\n  'friends.$': { type: String },\n}\n```\n\n**Note:** This only applies to shorthand definitions, not to the longhand definition. This example will throw an error `{ friends: { type: [String] } }` even though it was valid in [the meteor-version of this package](https://github.com/aldeed/meteor-simple-schema/).\n\n### Multiple Definitions For One Key\n\nYou can define two or more different ways in which a key will be considered valid:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  id: SimpleSchema.oneOf(String, SimpleSchema.Integer),\n  name: String,\n});\n```\n\nAnd this can be done in any mixture of shorthand and longhand:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  id: SimpleSchema.oneOf(\n    {\n      type: String,\n      min: 16,\n      max: 16,\n    },\n    {\n      type: SimpleSchema.Integer,\n      min: 0,\n    }\n  ),\n  name: String,\n});\n```\n\nWhen one of the allowed types is an object, use a subschema. Don't mix the object property definitions in with the main schema.\n\nCorrect:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst objSchema = new SimpleSchema({\n  _id: String,\n});\n\nconst schema = new SimpleSchema({\n  foo: SimpleSchema.oneOf(String, objSchema),\n});\n```\n\nIncorrect:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  foo: SimpleSchema.oneOf(String, Object),\n  \"foo._id\": {\n    type: String,\n    optional: true,\n  },\n});\n```\n\nNOTE: Multiple definitions is still an experimental feature and may not work as you expect in complex situations, such as where one of the valid definitions is an object or array. By reporting any weirdness you experience, you can help make it more robust.\n\n### Extending Schemas\n\nIf there are certain fields that are repeated in many of your schemas, it can be useful to define a SimpleSchema instance just for those fields and then merge them into other schemas:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\nimport { idSchema, addressSchema } from \"./sharedSchemas\";\n\nconst schema = new SimpleSchema({\n  name: String,\n});\nschema.extend(idSchema);\nschema.extend(addressSchema);\n```\n\n#### Overriding When Extending\n\nIf the key appears in both schemas, the definition will be extended such that the result is the combination of both definitions.\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\nimport { idSchema, addressSchema } from \"./sharedSchemas\";\n\nconst schema = new SimpleSchema({\n  name: {\n    type: String,\n    min: 5,\n  },\n});\nschema.extend({\n  name: {\n    type: String,\n    max: 15,\n  },\n});\n```\n\nThe above will result in the definition of the `name` field becoming:\n\n```js\n{\n  name: {\n    type: String,\n    min: 5,\n    max: 15,\n  },\n}\n```\n\nNote also that a plain object was passed to `extend`. If you pass a plain object, it is converted to a `SimpleSchema` instance for you.\n\n### Subschemas\n\nSimilar to extending, you can also reference other schemas as a way to define objects that occur within the main object:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\nimport { addressSchema } from \"./sharedSchemas\";\n\nconst schema = new SimpleSchema({\n  name: String,\n  homeAddress: addressSchema,\n  billingAddress: {\n    type: addressSchema,\n    optional: true,\n  },\n});\n```\n\n### Extracting Schemas\n\nSometimes you have one large SimpleSchema object, and you need just a subset of it for some purpose.\n\nTo pull out certain schema keys into a new schema, you can use the `pick` method:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  firstName: String,\n  lastName: String,\n  username: String,\n});\n\nconst nameSchema = schema.pick(\"firstName\", \"lastName\");\n```\n\nTo keep all but certain keys in a new schema, you can use the `omit` method:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  firstName: String,\n  lastName: String,\n  username: String,\n});\n\nconst nameSchema = schema.omit(\"username\");\n```\n\nTo pull a subschema out of an `Object` key in a larger schema, you can use `getObjectSchema`:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  firstName: String,\n  lastName: String,\n  address: Object,\n  \"address.street1\": String,\n  \"address.street2\": { type: String, optional: true },\n  \"address.city\": String,\n  \"address.state\": String,\n  \"address.postalCode\": String,\n});\n\nconst addressSchema = schema.getObjectSchema(\"address\");\n\n// addressSchema is now the same as this:\n// new SimpleSchema({\n//   street1: String,\n//   street2: { type: String, optional: true },\n//   city: String,\n//   state: String,\n//   postalCode: String,\n// });\n```\n\n### Raw Definition\n\nSometimes if you want to get the `rawDefinition` of some schema just pass in the options `{ keepRawDefinition: true}`(if not arg is passed the value will be null). Example:\n\n```javascript\nconst userSchema = new SimpleSchema(\n  {\n    name: String,\n    number: \"SimpleSchema.Integer\",\n    email: String,\n  },\n  { keepRawDefintion: true }\n);\nuserSchema.rawDefinition;\n//{\n//   name: String,\n//   number: 'SimpleSchema.Integer',\n//   email: String\n//}\n```\n\n## Schema Keys\n\nA basic schema key is just the name of the key (property) to expect in the objects that will be validated.\n\nUse string keys with MongoDB-style dot notation to validate nested arrays and objects. For example:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  mailingAddress: Object,\n  \"mailingAddress.street\": String,\n  \"mailingAddress.city\": String,\n});\n```\n\nTo indicate array items, use a `$`:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  addresses: {\n    type: Array,\n    minCount: 1,\n    maxCount: 4,\n  },\n  \"addresses.$\": Object,\n  \"addresses.$.street\": String,\n  \"addresses.$.city\": String,\n});\n```\n\n## Schema Rules\n\nHere are some specifics about the various rules you can define in your schema.\n\n### type\n\nOne of the following:\n\n- `String`\n- `Number`\n- `SimpleSchema.Integer` (same as `Number` but with decimals/floats disallowed)\n- `Boolean`\n- `Object`\n- `Array`\n- Any custom or built-in class like `Date`\n- Another `SimpleSchema` instance, meaning `Object` type with this schema\n- `SimpleSchema.oneOf(...)`, with multiple of the above types\n\n### label\n\n_Can also be a function that returns the label_\n\nA string that will be used to refer to this field in validation error messages. The default is an inflected (humanized) derivation of the key name itself. For example, the key \"firstName\" will have a default label of \"First name\" if you do not include the `label` property in your definition.\n\nYou can use the `labels` function to alter one or more labels on the fly:\n\n```js\nschema.labels({\n  password: \"Enter your password\",\n});\n```\n\nIf you have enabled Tracker reactivity, this method causes reactive labels to update.\n\nTo get the label for a field, use `schema.label(fieldName)`, which returns a usable string. If you have enabled Tracker reactivity, this method is reactive.\n\n### optional\n\n_Can also be a function that returns true or false_\n\nBy default, all keys are required. Set `optional: true` to change that.\n\nWith complex keys, it might be difficult to understand what \"required\" means. Here's a brief explanation of how requiredness is interpreted:\n\n- If `type` is `Array`, then \"required\" means that key must have a value, but an empty array is fine. (If an empty array is _not_ fine, add the `minCount: 1` option.)\n- For array items (when the key name ends with \".$\"), if `optional` is true, then `null` values are valid. If array items are required, then any `null` items will fail the type check.\n- If a key is required at a deeper level, the key must have a value _only if_ the object it belongs to is present.\n- When the object being validated is a Mongo modifier object, changes that would unset or `null` a required key result in validation errors.\n\nThat last point can be confusing, so let's look at a couple examples:\n\n- Say you have a required key \"friends.address.city\" but \"friends.address\" is optional. If \"friends.address\" is set in the object you're validating, but \"friends.address.city\" is not, there is a validation error. However, if \"friends.address\" is _not_ set, then there is no validation error for \"friends.address.city\" because the object it belongs to is not present.\n- If you have a required key \"friends.$.name\", but the `friends` array has no objects in the object you are validating, there is no validation error for \"friends.$.name\". When the `friends` array _does_ have objects, every present object is validated, and each object could potentially have a validation error if it is missing the `name` property. For example, when there are two objects in the friends array and both are missing the `name` property, there will be a validation error for both \"friends.0.name\" and \"friends.1.name\".\n\n### required\n\n_Can also be a function that returns true or false_\n\nIf you would rather have all your schema keys be optional by default, pass the `requiredByDefault: false` option and then use `required: true` to make individual keys required.\n\n```js\nconst schema = new SimpleSchema(\n  {\n    optionalProp: String,\n    requiredProp: { type: String, required: true },\n  },\n  { requiredByDefault: false }\n);\n```\n\n### min/max\n\n_Can also be a function that returns the min/max value_\n\n- If `type` is `Number` or `SimpleSchema.Integer`, these rules define the minimum or maximum numeric value.\n- If `type` is `String`, these rules define the minimum or maximum string length.\n- If `type` is `Date`, these rules define the minimum or maximum date, inclusive.\n\nYou can alternatively provide a function that takes no arguments and returns the appropriate minimum or maximum value. This is useful, for example, if the minimum Date for a field should be \"today\".\n\n### exclusiveMin/exclusiveMax\n\n_Can also be a function that returns true or false_\n\nSet to `true` to indicate that the range of numeric values, as set by min/max, are to be treated as an exclusive range. Set to `false` (default) to treat ranges as inclusive.\n\n### minCount/maxCount\n\n_Can also be a function that returns the minCount/maxCount value_\n\nDefine the minimum or maximum array length. Used only when type is `Array`.\n\n### allowedValues\n\n_Can also be a function that returns the array or the `Set` of allowed values_\n\nAn array or a `Set` of values that are allowed. A key will be invalid if its value is not one of these.\n\nYou can use `schema.getAllowedValuesForKey(key)` to get the allowed values array for a key.\n\n**Note**: If you wish to restrict the items allowed in an `Array`, the `allowedValues` property must be on the array item definition.\n\n```javascript\nconst schema = new SimpleSchema({\n  myArray: {\n    type: Array,\n  },\n  \"myArray.$\": {\n    type: String,\n    allowedValues: [\"foo\", \"bar\"],\n  },\n});\n```\n\n### regEx\n\n_Can also be a function that returns a regular expression or an array of them_\n\nAny regular expression that must be matched for the key to be valid, or an array of regular expressions that will be tested in order.\n\nThe `SimpleSchema.RegEx` object defines standard regular expressions you can use as the value for the `regEx` key.\n\n- `SimpleSchema.RegEx.Email` for emails (uses a permissive regEx recommended by W3C, which most browsers use. Does not require a TLD)\n- `SimpleSchema.RegEx.EmailWithTLD` for emails that must have the TLD portion (.com, etc.). Emails like `me@localhost` and `me@192.168.1.1` won't pass this one.\n- `SimpleSchema.RegEx.Domain` for external domains and the domain only (requires a tld like `.com`)\n- `SimpleSchema.RegEx.WeakDomain` for less strict domains and IPv4 and IPv6\n- `SimpleSchema.RegEx.IP` for IPv4 or IPv6\n- `SimpleSchema.RegEx.IPv4` for just IPv4\n- `SimpleSchema.RegEx.IPv6` for just IPv6\n- `SimpleSchema.RegEx.Url` for http, https and ftp urls\n- `SimpleSchema.RegEx.Id` for IDs generated by `Random.id()` of the random package, also usable to validate a relation id.\n- `SimpleSchema.RegEx.idOfLength(min, max)` for IDs generated by `Random.id(length)` where min/max define lower and upper bounds.\n  Call without params for allowing an arbitrary length. Call with `min` only for fixed length.\n  Call with `max = null` for fixed lower and arbitrary upper bounds.\n- `SimpleSchema.RegEx.ZipCode` for 5- and 9-digit ZIP codes\n- `SimpleSchema.RegEx.Phone` for phone numbers (taken from Google's libphonenumber library)\n\n### skipRegExCheckForEmptyStrings\n\n_Can also be a function that returns true or false_\n\nSet to `true` when `regEx` is set if you want an empty string to always pass validation, even though the regular expression may disallow it.\n\n### blackbox\n\nIf you have a key with type `Object`, the properties of the object will be validated as well, so you must define all allowed properties in the schema. If this is not possible or you don't care to validate the object's properties, use the `blackbox: true` option to skip validation for everything within the object.\n\nPrior to SimpleSchema 2.0, objects that are instances of a custom class were considered to be blackbox by default. This is no longer true, so if you do not want your class instance validated, be sure to add `blackbox: true` in your schema.\n\n### trim\n\n_Used by the cleaning process but not by validation_\n\nWhen you call `simpleSchemaInstance.clean()` with `trimStrings` set to `true`, all string values are trimmed of leading and trailing whitespace. If you set `trim` to `false` for certain keys in their schema definition, those keys will be skipped.\n\n### custom\n\nRefer to the [Custom Validation](#custom-field-validation) section.\n\n### defaultValue\n\n_Used by the cleaning process but not by validation_\n\nSet this to any value that you want to be used as the default when an object does not include this field or has this field set to `undefined`. This value will be injected into the object by a call to `mySimpleSchema.clean()` with `getAutovalues: true`.\n\nNote the following points of confusion:\n\n- A default value itself is not cleaned. So, for example, if your default value is \"\", it will not be removed by the `removeEmptyStrings` operation in the cleaning.\n- A default value is added only if there isn't a value set AND the parent object exists. Usually this is what you want, but if you need to ensure that it will always be added, you can add `defaultValue: {}` to all ancestor objects.\n\nIf you need more control, use the `autoValue` option instead.\n\nTo get the defaultValue for a field, use `schema.defaultValue(fieldName)`. It is a shorthand for [`schema.get(fieldName, 'defaultValue')`](#getting-field-properties).\n\n### autoValue\n\n_Used by the cleaning process but not by validation_\n\nThe `autoValue` option allows you to specify a function that is called by `simpleSchemaInstance.clean()` to potentially change the value of a property in the object being cleaned. This is a powerful feature that allows you to set up either forced values or default values, potentially based on the values of other fields in the object.\n\nAn `autoValue` function `this` context provides a variety of properties and methods to help you determine what you should return:\n\n- `this.closestSubschemaFieldName`: If your schema is used as a subschema in another schema, this will be set to the name of the key that references the schema. Otherwise it will be `null`.\n- `this.field()`: Use this method to get information about other fields. Pass a field name (schema key) as the only argument. The return object will have `isSet`, `value`, and `operator` properties for that field.\n- `this.genericKey`: The generic schema key for which the autoValue is running (`$` in place of actual array index).\n- `this.isInArrayItemObject`: True if we're traversing an object that's in an array.\n- `this.isInSubObject`: True if we're traversing an object that's somewhere within another object.\n- `this.isModifier`: True if this is running on a MongoDB modifier object.\n- `this.isSet`: True if the field is already set in the document or modifier\n- `this.key`: The schema key for which the autoValue is running. This is usually known, but if your autoValue function is shared among various keys or if your schema is used as a subschema in another schema, this can be useful.\n- `this.obj`: The full object.\n- `this.operator`: If isSet = true and isUpdate = true, this contains the name of the update operator in the modifier in which this field is being changed. For example, if the modifier were `{$set: {name: \"Alice\"}}`, in the autoValue function for the `name` field, `this.isSet` would be true, `this.value` would be \"Alice\", and `this.operator` would be \"$set\".\n- `this.parentField()`: Use this method to get information about the parent object. Works the same way as `field()`.\n- `this.siblingField()`: Use this method to get information about other fields that have the same parent object. Works the same way as `field()`. This is helpful when you use sub-schemas or when you're dealing with arrays of objects.\n- `this.unset()`: Call this method to prevent the original value from being used when you return undefined.\n- `this.value`: If isSet = true, this contains the field's current (requested) value in the document or modifier.\n\nIf an `autoValue` function does not return anything (i.e., returns `undefined`), the field's value will be whatever the document or modifier says it should be. If that field is already in the document or modifier, it stays in the document or modifier with the same value. If it's not in the document or modifier, it's still not there. If you don't want it to be in the doc or modifier, you must call `this.unset()`.\n\nAny other return value will be used as the field's value. You may also return special pseudo-modifier objects for update operations. Examples are `{$inc: 1}` and `{$push: new Date}`.\n\n#### autoValue gotchas\n\n- If your autoValue for one field relies on the autoValue or defaultValue of another field, make sure that the other field is listed before the field that relies on it in the schema. autoValues are run in order from least nested, to most nested, so you can assume that parent values will be set, but for fields at the same level, schema order matters. Refer to [issue #204](https://github.com/Meteor-Community-Packages/meteor-simple-schema/issues/204).\n- An `autoValue` function will always run during cleaning even if that field is not in the object being cleaned. This allows you to provide complex default values. If your function applies only when there is a value, you should add `if (!this.isSet) return;` at the top.\n\n### Function Properties\n\nYou may have noticed that many of the rule properties can be set to functions that return the value. If you do this, the `this` context within those functions will have the following properties:\n\n- `this.field()`: Use this method to get information about other fields. Pass a field name (schema key) as the only argument. The return object will have `isSet`, `value`, and `operator` properties for that field.\n- `this.genericKey`: The generic schema key for which the autoValue is running (`$` in place of actual array index).\n- `this.isInArrayItemObject`: True if we're traversing an object that's in an array.\n- `this.isInSubObject`: True if we're traversing an object that's somewhere within another object.\n- `this.isModifier`: True if this is running on a MongoDB modifier object.\n- `this.isSet`: True if the field is already set in the document or modifier\n- `this.key`: The schema key for which the autoValue is running. This is usually known, but if your autoValue function is shared among various keys or if your schema is used as a subschema in another schema, this can be useful.\n- `this.obj`: The full object.\n- `this.operator`: If isSet = true and isUpdate = true, this contains the name of the update operator in the modifier in which this field is being changed. For example, if the modifier were `{$set: {name: \"Alice\"}}`, in the autoValue function for the `name` field, `this.isSet` would be true, `this.value` would be \"Alice\", and `this.operator` would be \"$set\".\n- `this.parentField()`: Use this method to get information about the parent object. Works the same way as `field()`.\n- `this.siblingField()`: Use this method to get information about other fields that have the same parent object. Works the same way as `field()`. This is helpful when you use sub-schemas or when you're dealing with arrays of objects.\n- `this.validationContext`: The current validation context\n- `this.value`: If isSet = true, this contains the field's current (requested) value in the document or modifier.\n\n### Getting field properties\n\nTo obtain field's property value, just call the `get` method.\n\n```js\nconst schema = new SimpleSchema({\n  friends: {\n    type: Array,\n    minCount: 0,\n    maxCount: 3,\n  },\n});\n\nschema.get(\"friends\", \"maxCount\"); // 3\n```\n\n## Validating Data\n\n### The Object to Validate\n\nThe object you pass in when validating can be a normal object, or it can be\na Mongo modifier object (with `$set`, etc. keys). In other words, you can pass\nin the exact object that you are going to pass to `Collection.insert()` or\n`Collection.update()`. This is what the [collection2](https://atmospherejs.com/aldeed/collection2) package does for you.\n\n### Ways to Perform Validation\n\nThere are three ways to validate an object against your schema:\n\n1. With a throwaway context, throwing an Error for the first validation error found (schema.validate())\n1. With a unique unnamed validation context, not throwing any Errors (schema.newContext().validate())\n1. With a unique named validation context, not throwing any Errors (schema.namedContext('someUniqueString').validate())\n1. With the default validation context, not throwing any Errors. (schema.namedContext().validate())\n\nA validation context provides reactive methods for validating and checking the validation status of a particular object.\n\n#### Named Validation Contexts\n\nIt's usually best to use a named validation context. That way, the context is automatically persisted by name, allowing you to easily rely on its reactive methods.\n\nHere is an example of obtaining a named validation context:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  name: String,\n});\n\nconst userFormValidationContext = schema.namedContext(\"userForm\");\n```\n\nThe first time you request a context with a certain name, it is created. Calling `namedContext()` passing no arguments is equivalent to calling `namedContext('default')`.\n\n#### Unnamed Validation Contexts\n\nTo obtain an unnamed validation context, call `newContext()`:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  name: String,\n});\n\nconst myValidationContext = schema.newContext();\n```\n\nAn unnamed validation context is not persisted anywhere. It can be useful when you need to see if a document is valid but you don't need any of the reactive methods for that context, or if you are going to keep the context reference in memory yourself.\n\n### Validating an Object\n\nTo validate an object against the schema in a validation context, call `validationContextInstance.validate(obj, options)`. This method returns `true` if the object is valid according to the schema or `false` if it is not. It also stores a list of invalid fields and corresponding error messages in the context object and causes the reactive methods to react if you injected Tracker reactivity.\n\nYou can call `myContext.isValid()` to see if the object last passed into `validate()` was found to be valid. This is a reactive method that returns `true` or `false`.\n\nFor a list of options, see the [Validation Options](#validation-options) section.\n\n### Validating Only Some Keys in an Object\n\nYou may have the need to (re)validate certain keys while leaving any errors for other keys unchanged. For example, if you have several errors on a form and you want to revalidate only the invalid field the user is currently typing in. For this situation, call `myContext.validate` with the `keys` option set to an array of keys that should be validated. This may cause all of the reactive methods to react.\n\nThis method returns `true` only if all the specified schema keys and their descendent keys are valid according to the schema. Otherwise it returns `false`.\n\n### Validation Options\n\n`validate()` accepts the following options:\n\n- `modifier`: Are you validating a Mongo modifier object? False by default.\n- `upsert`: Are you validating a Mongo modifier object potentially containing upsert operators? False by default.\n- `extendedCustomContext`: This object will be added to the `this` context in any custom validation functions that are run during validation. See the [Custom Validation](#custom-validation) section.\n- `ignore`: An array of validation error types (in SimpleSchema.ErrorTypes enum) to ignore.\n- `keys`: An array of keys to validate. If not provided, revalidates the entire object.\n\n### Validating and Throwing ValidationErrors\n\n- Call `mySimpleSchema.validate(obj, options)` to validate `obj` against the schema and throw a `ValidationError` if invalid.\n- Call `SimpleSchema.validate(obj, schema, options)` static function as a shortcut for `mySimpleSchema.validate` if you don't want to create `mySimpleSchema` first. The `schema` argument can be just the schema object, in which case it will be passed to the `SimpleSchema` constructor for you. This is like `check(obj, schema)` but without the `check` dependency and with the ability to pass full schema error details back to a callback on the client.\n- Call `mySimpleSchema.validator()` to get a function that calls `mySimpleSchema.validate` for whatever object is passed to it. This means you can do `validate: mySimpleSchema.validator()` in the [mdg:validated-method](https://github.com/meteor/validated-method) package.\n- Call `mySimpleSchema.getFormValidator()` to get a function that validates whatever object is passed to it and returns a Promise that resolves with errors. The returned function is compatible with the [Composable Form Specification](http://forms.dairystatedesigns.com/user/validation/).\n\n#### Customize the Error That is Thrown\n\nYou can `defineValidationErrorTransform` one time somewhere in your code to customize the error or change it to a more specific type.\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nSimpleSchema.defineValidationErrorTransform((error) =\u003e {\n  const customError = new MyCustomErrorType(error.message);\n  customError.errorList = error.details;\n  return customError;\n});\n```\n\nFor example, in a Meteor app, in order to ensure that the error details are sent back to the client when throwing an error in a server method, you can convert it to a `Meteor.Error`:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nSimpleSchema.defineValidationErrorTransform((error) =\u003e {\n  const ddpError = new Meteor.Error(error.message);\n  ddpError.error = \"validation-error\";\n  ddpError.details = error.details;\n  return ddpError;\n});\n```\n\n### Custom Field Validation\n\nThere are three ways to attach custom validation methods.\n\nTo add a custom validation function that is called for ALL keys in ALL schemas (for example, to publish a package that adds global support for some additional rule):\n\n```js\nSimpleSchema.addValidator(myFunction);\n```\n\nTo add a custom validation function that is called for ALL keys for ONE schema:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({ ... });\nschema.addValidator(myFunction);\n```\n\nTo add a custom validation function that is called for ONE key in ONE schema:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({\n  someKey: {\n    type: String,\n    custom: myFunction,\n  },\n});\n```\n\nAll custom validation functions work the same way. First, do the necessary custom validation, use `this` to get whatever information you need. Then, if valid, return `undefined`. If invalid, return an error type string. The error type string can be one of the [built-in strings](#manually-adding-a-validation-error) or any string you want.\n\n- If you return a built-in string, it's best to use the `SimpleSchema.ErrorTypes` constants.\n- If you return a custom string, you'll usually want to [define a message for it](#customizing-validation-messages).\n\nWithin your custom validation function, `this` provides the following properties:\n\n- `key`: The name of the schema key (e.g., \"addresses.0.street\")\n- `genericKey`: The generic name of the schema key (e.g., \"addresses.$.street\")\n- `definition`: The schema definition object.\n- `isSet`: Does the object being validated have this key set?\n- `value`: The value to validate.\n- `operator`: The Mongo operator for which we're doing validation. Might be `null`.\n- `validationContext`: The current `ValidationContext` instance\n- `field()`: Use this method to get information about other fields. Pass a field name (non-generic schema key) as the only argument. The return object will have `isSet`, `value`, and `operator` properties for that field.\n- `siblingField()`: Use this method to get information about other fields that have the same parent object. Works the same way as `field()`. This is helpful when you use sub-schemas or when you're dealing with arrays of objects.\n- `addValidationErrors(errors)`: Call this to add validation errors for any key. In general, you should use this to add errors for other keys. To add an error for the current key, return the error type string. If you do use this to add an error for the current key, return `false` from your custom validation function.\n\nNOTE: If you need to do some custom validation on the server and then display errors back\non the client, refer to the [Asynchronous Custom Validation on the Client](#asynchronous-custom-validation-on-the-client) section.\n\n### Custom Whole-Document Validators\n\nAdd a validator for all schemas:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nSimpleSchema.addDocValidator((obj) =\u003e {\n  // Must return an array, potentially empty, of objects with `name` and `type` string properties and optional `value` property.\n  return [{ name: \"firstName\", type: \"TOO_SILLY\", value: \"Reepicheep\" }];\n});\n```\n\nAdd a validator for one schema:\n\n```js\nimport SimpleSchema from \"meteor/aldeed:simple-schema\";\n\nconst schema = new SimpleSchema({ ... });\nschema.addDocValidator(obj =\u003e {\n  // Must return an array, potentially empty, of objects with `name` and `type` string properties and optional `value` property.\n  return [\n    { name: 'firstName', type: 'TOO_SILLY', value: 'Reepicheep' }\n  ];\n});\n```\n\nWhole-document validators have the following available on `this` context:\n\n- `this.ignoreTypes`: The value of the `ignore` option that was passed to `validate`.\n- `this.isModifier`: True if this is running on a MongoDB modifier object.\n- `this.isUpsert`: True if this is running on a MongoDB modifier object that is for an upsert.\n- `this.keysToValidate`: The value of the `keys` option that was passed to `validate`.\n- `this.mongoObject`: The `MongoObject` instance.\n- `this.obj`: The full object.\n- `this.schema`: The schema instance.\n- `this.validationContext`: The `ValidationContext` instance.\n\n### Manually Adding a Validation Error\n\nIf you want to reactively display an arbitrary validation error and it is not possible to use a custom validation function (perhaps you have to call a function `onSubmit` or wait for asynchronous results), you can add one or more errors to a validation context at any time by calling `myContext.addValidationErrors(errors)`, where `errors` is an array of error objects with the following format:\n\n```js\n{name: key, type: errorType, value: anyValue}\n```\n\n- `name`: The schema key as specified in the schema.\n- `type`: The type of error. Any string you want, or one of the strings in the `SimpleSchema.ErrorTypes` list.\n- `value`: Optional. The value that was not valid. Will be used to replace the `[value]` placeholder in error messages.\n\nIf you use a custom string for `type`, be sure to define a message for it. (See [Customizing Validation Messages](#customizing-validation-messages)).\n\nExample:\n\n```js\nSimpleSchema.setDefaultMessages({\n  messages: {\n    en: {\n      wrongPassword: \"Wrong password\",\n    },\n  },\n});\n\nmyValidationContext.addValidationErrors([\n  { name: \"password\", type: \"wrongPassword\" },\n]);\n```\n\n### Asynchronous Custom Validation on the Client\n\nNOTE: To use the `unique` option in this example, you need to be in a Meteor app with the `aldeed:schema-index` package added.\n\nValidation runs synchronously for many reasons, and likely always will. This makes it difficult to wait for asynchronous results as part of custom validation. Here's one example of how you might validate that a username is unique on the client, without publishing all usernames to every client:\n\n```js\nusername: {\n  type: String,\n  regEx: /^[a-z0-9A-Z_]{3,15}$/,\n  unique: true,\n  custom() {\n    if (Meteor.isClient \u0026\u0026 this.isSet) {\n      Meteor.call(\"accountsIsUsernameAvailable\", this.value, (error, result) =\u003e {\n        if (!result) {\n          this.validationContext.addValidationErrors([{\n            name: \"username\",\n            type: \"notUnique\"\n          }]);\n        }\n      });\n    }\n  }\n}\n```\n\nNote that we're calling our \"accountsIsUsernameAvailable\" server method and waiting for an asynchronous result, which is a boolean that indicates whether that username is available. If it's taken, we manually invalidate the `username` key with a \"notUnique\" error.\n\nThis doesn't change the fact that validation is synchronous. If you use this with an autoform and there are no validation errors, the form would still be submitted. However, the user creation would fail and a second or two later, the form would display the \"notUnique\" error, so the end result is very similar to actual asynchronous validation.\n\nYou can use a technique similar to this to work around asynchronicity issues in both client and server code.\n\n### Getting a List of Invalid Keys and Validation Error Messages\n\n_This is a reactive method if you have enabled Tracker reactivity._\n\nCall `myValidationContext.validationErrors()` to get the full array of validation errors. Each object in the array has at least two keys:\n\n- `name`: The schema key as specified in the schema.\n- `type`: The type of error. See `SimpleSchema.ErrorTypes`.\n\nThere may also be a `value` property, which is the value that was invalid.\n\nThere may be a `message` property, but usually the error message is constructed from message templates. You should call `ctxt.keyErrorMessage(key)` to get a reactive message string rather than using `error.message` directly.\n\n## Customizing Validation Messages\n\nError messages are managed by the [message-box](https://github.com/aldeed/node-message-box) package.\n\nIn most cases you probably want to set default messages to be used by all `SimpleSchema` instances. Example:\n\n```js\nSimpleSchema.setDefaultMessages({\n  messages: {\n    en: {\n      too_long: \"Too long!\",\n    },\n  },\n});\n```\n\nThe object syntax is the same as shown [here](https://github.com/aldeed/node-message-box#defining-messages) for `MessageBox.defaults`. When you call `setDefaultMessages`, it simply extends [the default defaults](https://github.com/Meteor-Community-Packages/meteor-simple-schema/blob/main/package/lib/defaultMessages.js#L18). **Be sure to call it before you create any of your SimpleSchema instances**\n\nThe `MessageBox` instance for a specific schema instance is `simpleSchemaInstance.messageBox`. You can call `messages` function on this to update the messages for that schema only. Example:\n\n```js\nsimpleSchemaInstance.messageBox.messages({\n  en: {\n    too_long: \"Too long!\",\n  },\n});\n```\n\n## Other Validation Context Methods\n\n`myContext.keyIsInvalid(key)` returns true if the specified key is currently\ninvalid, or false if it is valid. This is a reactive method.\n\n`myContext.keyErrorMessage(key)` returns the error message for the specified\nkey if it is invalid. If it is valid, this method returns an empty string. This\nis a reactive method.\n\nCall `myContext.reset()` if you need to reset the validation context, clearing out any invalid field messages and making it valid.\n\n`myContext.name` is set to the context name, if it is a named context. Create named contexts by calling `schema.namedContext(name)` or `new ValidationContext(schema, name)`.\n\n## Other SimpleSchema Methods\n\nCall `MySchema.schema([key])` to get the schema definition object. If you specify a key, then only the schema definition for that key is returned.\n\nNote that this may not match exactly what you passed into the SimpleSchema constructor. The schema definition object is normalized internally, and this method returns the normalized copy.\n\n## Cleaning Objects\n\nYou can call `simpleSchemaInstance.clean()` or `simpleSchemaValidationContextInstance.clean()` to clean the object you're validating. Do this prior to validating it to avoid any avoidable validation errors.\n\nThe `clean` function takes the object to be cleaned as its first argument and the following optional options as its second argument:\n\n- `mutate`: The object is copied before being cleaned. If you don't mind mutating the object you are cleaning, you can pass `mutate: true` to get better performance.\n- `isModifier`: Is the first argument a modifier object? False by default.\n- `filter`: `true` by default. If `true`, removes any keys not explicitly or implicitly allowed by the schema, which prevents errors being thrown for those keys during validation.\n- `autoConvert`: `true` by default. If `true`, helps eliminate unnecessary validation messages by automatically converting values where possible.\n  - Non-string values are converted to a String if the schema expects a String\n  - Strings that are numbers are converted to Numbers if the schema expects a Number\n  - Strings that are \"true\" or \"false\" are converted to Boolean if the schema expects a Boolean\n  - Numbers are converted to Boolean if the schema expects a Boolean, with 0 being `false` and all other numbers being `true`\n  - Non-array values are converted to a one-item array if the schema expects an Array\n- `removeEmptyStrings`: Remove keys in normal object or $set where the value is an empty string? True by default.\n- `trimStrings`: Remove all leading and trailing spaces from string values? True by default.\n- `getAutoValues`: Run `autoValue` functions and inject automatic and `defaultValue` values? True by default.\n- `extendAutoValueContext`: This object will be added to the `this` context of autoValue functions. `extendAutoValueContext` can be used to give your `autoValue` functions additional valuable information, such as `userId`. (Note that operations done using the Collection2 package automatically add `userId` to the `autoValue` context already.)\n\nYou can also set defaults for any of these options in your SimpleSchema constructor options:\n\n```js\nconst schema = new SimpleSchema(\n  {\n    name: String,\n  },\n  {\n    clean: {\n      trimStrings: false,\n    },\n  }\n);\n```\n\nNOTE: The Collection2 package always calls `clean` before every insert, update, or upsert.\n\n## Dates\n\nFor consistency, if you care only about the date (year, month, date) portion and not the time, then use a `Date` object set to the desired date at midnight UTC _(note, the clean function won't strip out time)_. This goes for `min` and `max` dates, too. If you care only about the date\nportion and you want to specify a minimum date, `min` should be set to midnight UTC on the minimum date (inclusive).\n\nFollowing these rules ensures maximum interoperability with HTML5 date inputs and usually just makes sense.\n\n## Best Practice Code Examples\n\n### Make a field conditionally required\n\nIf you have a field that should be required only in certain circumstances, first make the field\noptional, and then use a custom function similar to this:\n\n```js\n{\n  field: {\n    type: String,\n    optional: true,\n    custom: function () {\n      let shouldBeRequired = this.field('saleType').value === 1;\n\n      if (shouldBeRequired) {\n        // inserts\n        if (!this.operator) {\n          if (!this.isSet || this.value === null || this.value === \"\") return SimpleSchema.ErrorTypes.REQUIRED;\n        }\n\n        // updates\n        else if (this.isSet) {\n          if (this.operator === \"$set\" \u0026\u0026 this.value === null || this.value === \"\") return SimpleSchema.ErrorTypes.REQUIRED;\n          if (this.operator === \"$unset\") return SimpleSchema.ErrorTypes.REQUIRED;\n          if (this.operator === \"$rename\") return SimpleSchema.ErrorTypes.REQUIRED;\n        }\n      }\n    }\n  }\n}\n```\n\nWhere `customCondition` is whatever should trigger it being required.\n\n### Validate one key against another\n\nHere's an example of declaring one value valid or invalid based on another\nvalue using a custom validation function.\n\n```js\nSimpleSchema.messageBox.messages({\n  en: {\n    passwordMismatch: \"Passwords do not match\",\n  },\n});\n\nMySchema = new SimpleSchema({\n  password: {\n    type: String,\n    label: \"Enter a password\",\n    min: 8,\n  },\n  confirmPassword: {\n    type: String,\n    label: \"Enter the password again\",\n    min: 8,\n    custom() {\n      if (this.value !== this.field(\"password\").value) {\n        return \"passwordMismatch\";\n      }\n    },\n  },\n});\n```\n\n### Translation of Regular Expression Messages\n\nThe built-in English messages for regular expressions use a function, so to provide similar messages in another language, you can also use a function with a switch statement:\n\n```js\nmessages: {\n  fr: {\n    regEx({ label, regExp }) {\n                switch (regExp) {\n                    case (SimpleSchema.RegEx.Email.toString()):\n                    case (SimpleSchema.RegEx.EmailWithTLD.toString()):\n                        return \"Cette adresse e-mail est incorrecte\";\n                    case (SimpleSchema.RegEx.Domain.toString()):\n                    case (SimpleSchema.RegEx.WeakDomain.toString()):\n                        return \"Ce champ doit être un domaine valide\";\n                    case (SimpleSchema.RegEx.IP.toString()):\n                        return \"Cette adresse IP est invalide\";\n                    case (SimpleSchema.RegEx.IPv4.toString()):\n                        return \"Cette adresse IPv4 est invalide\";\n                    case (SimpleSchema.RegEx.IPv6.toString()):\n                        return \"Cette adresse IPv6 est invalide\";\n                    case (SimpleSchema.RegEx.Url.toString()):\n                        return \"Cette URL est invalide\";\n                    case (SimpleSchema.RegEx.Id.toString()):\n                        return \"Cet identifiant alphanumérique est invalide\";\n                    case (SimpleSchema.RegEx.ZipCode.toString()):\n                        return \"Ce code postal est invalide\";\n                    case (SimpleSchema.RegEx.Phone.toString()):\n                        return \"Ce numéro de téléphone est invalide\";\n                    default:\n                        return \"Ce champ n'a pas passé la validation Regex\";\n                }\n            },\n    }\n  }\n}\n```\n\n## Debug Mode\n\nSet `SimpleSchema.debug = true` in your app before creating any named\nvalidation contexts to cause all named validation contexts to automatically\nlog all invalid key errors to the browser console. This can be helpful while\ndeveloping an app to figure out why certain actions are failing validation.\n\n## Extending the Schema Options\n\nYou may find at some point that there is something extra you would really like to define within a schema for your package or app. However, if you add unrecognized options to your schema definition, you will get an error. To inform SimpleSchema about your custom option and avoid the error, you need to call `SimpleSchema.extendOptions`. By way of example, here is how the Collection2 package adds the additional schema options it provides:\n\n```js\nSimpleSchema.extendOptions([\"index\", \"unique\", \"denyInsert\", \"denyUpdate\"]);\n```\n\nObviously you need to ensure that `extendOptions` is called before any SimpleSchema instances are created with those options.\n\n## Add On Packages\n\n[mxab:simple-schema-jsdoc](https://atmospherejs.com/mxab/simple-schema-jsdoc) Generate jsdoc from your schemas.\n\n(Submit a PR to list your package here)\n\n## Contributors\n\nThis project exists thanks to all the people who contribute.\n\n\u003ca href=\"graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/simple-schema-js/contributors.svg?width=890\" /\u003e\u003c/a\u003e\n\n## License\n\nMIT\n\n## Contributing\n\nAnyone is welcome to contribute. Before submitting a pull request, make sure that you've read our\n[contribution guide](CONTRIBUTING.md).\n\n### Thanks\n\n(Add your name if it's missing.)\n\n- @mquandalle\n- @Nemo64\n- @DavidSichau\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteor-community-packages%2Fmeteor-simple-schema","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeteor-community-packages%2Fmeteor-simple-schema","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeteor-community-packages%2Fmeteor-simple-schema/lists"}