{"id":13763744,"url":"https://github.com/Meteor-Community-Packages/meteor-collection2","last_synced_at":"2025-05-10T17:30:54.194Z","repository":{"id":9654718,"uuid":"11591774","full_name":"Meteor-Community-Packages/meteor-collection2","owner":"Meteor-Community-Packages","description":"A Meteor package that extends Mongo.Collection to provide support for specifying a schema and then validating against that schema when inserting and updating.","archived":false,"fork":false,"pushed_at":"2025-04-25T10:00:28.000Z","size":1073,"stargazers_count":1023,"open_issues_count":33,"forks_count":109,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-05-01T09:01:56.571Z","etag":null,"topics":["collection","database","hacktoberfest","meteor","meteorjs","mongo","mongodb","schema","validation"],"latest_commit_sha":null,"homepage":"https://packosphere.com/aldeed/collection2","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,"zenodo":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:32:43.000Z","updated_at":"2025-03-04T10:53:51.000Z","dependencies_parsed_at":"2023-01-11T17:40:10.655Z","dependency_job_id":"250915ae-95b7-4e85-8bf6-09b71a43c16b","html_url":"https://github.com/Meteor-Community-Packages/meteor-collection2","commit_stats":{"total_commits":386,"total_committers":39,"mean_commits":9.897435897435898,"dds":0.5207253886010363,"last_synced_commit":"230a11514c340ad7778d35bf3e2fe3af872f2053"},"previous_names":["aldeed/meteor-collection2"],"tags_count":82,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-collection2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-collection2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-collection2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Meteor-Community-Packages%2Fmeteor-collection2/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-collection2/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253453203,"owners_count":21911058,"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":["collection","database","hacktoberfest","meteor","meteorjs","mongo","mongodb","schema","validation"],"created_at":"2024-08-03T15:00:57.608Z","updated_at":"2025-05-10T17:30:54.182Z","avatar_url":"https://github.com/Meteor-Community-Packages.png","language":"JavaScript","funding_links":["https://github.com/sponsors/storytellercz","https://github.com/sponsors/jankapunkt"],"categories":["Collections","Packages"],"sub_categories":[],"readme":"# Collection2 (aldeed:collection2 Meteor package)\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-collection2)\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n![OSSF-Scorecard Score](https://img.shields.io/ossf-scorecard/github.com/Meteor-Community-Packages/meteor-collection2)\n![GitHub tag (latest SemVer)](https://img.shields.io/github/v/tag/Meteor-Community-Packages/meteor-collection2?label=latest\u0026sort=semver)\n[![](https://img.shields.io/badge/semver-2.0.0-success)](http://semver.org/spec/v2.0.0.html) \n![Test suite](https://github.com/Meteor-Community-Packages/meteor-collection2/workflows/Test%20suite/badge.svg)\n\n\nA Meteor package that allows you to attach a schema to a Mongo.Collection. Automatically validates against that schema when inserting and updating from client or server code.\n\nThis package requires the [simpl-schema](https://github.com/aldeed/simple-schema-js) NPM package, which defines the schema syntax and provides the validation logic.\n\n## TOC\n\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- [Installation](#installation)\n- [Import using static imports](#import-using-static-imports)\n- [Import using dynamic imports](#import-using-dynamic-imports)\n- [Why Use Collection2](#why-use-collection2)\n- [Attaching a Schema to a Collection](#attaching-a-schema-to-a-collection)\n  - [Attaching Multiple Schemas to the Same Collection](#attaching-multiple-schemas-to-the-same-collection)\n  - [attachSchema options](#attachschema-options)\n    - [transform](#transform)\n    - [replace](#replace)\n  - [Attach a Schema to Meteor.users](#attach-a-schema-to-meteorusers)\n- [Schema Format](#schema-format)\n- [Schema Clean Options](#schema-clean-options)\n- [Passing Options](#passing-options)\n- [Validation Contexts](#validation-contexts)\n- [Validating Without Inserting or Updating](#validating-without-inserting-or-updating)\n- [Inserting or Updating Without Validating](#inserting-or-updating-without-validating)\n- [Inserting or Updating Without Cleaning](#inserting-or-updating-without-cleaning)\n  - [Skip removing properties that are not in the schema](#skip-removing-properties-that-are-not-in-the-schema)\n  - [Skip conversion of values to match what schema expects](#skip-conversion-of-values-to-match-what-schema-expects)\n  - [Skip removing empty strings](#skip-removing-empty-strings)\n  - [Skip generating automatic values](#skip-generating-automatic-values)\n  - [Pick or omit from the attached schema](#pick-or-omit-from-the-attached-schema)\n- [Inserting or Updating Bypassing Collection2 Entirely](#inserting-or-updating-bypassing-collection2-entirely)\n- [Additional SimpleSchema Options](#additional-simpleschema-options)\n  - [index and unique](#index-and-unique)\n  - [denyInsert and denyUpdate](#denyinsert-and-denyupdate)\n  - [autoValue](#autovalue)\n  - [custom](#custom)\n- [What Happens When The Document Is Invalid?](#what-happens-when-the-document-is-invalid)\n- [More Details](#more-details)\n- [Community Add-On Packages](#community-add-on-packages)\n  - [Automatic Migrations](#automatic-migrations)\n- [Problems](#problems)\n  - [SubObjects and Arrays of Objects](#subobjects-and-arrays-of-objects)\n- [Disable displaying collection name in error message](#disable-displaying-collection-name-in-error-message)\n- [Contributors](#contributors)\n  - [Major Code Contributors](#major-code-contributors)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Installation\n\nIn your Meteor app directory, enter:\n\n### 4.0\n\nStarting 4.0 collection2 ships with built in [`aldeed:simple-schema@1.13.1`](https://github.com/Meteor-Community-Packages/meteor-simple-schema/releases/tag/v1.13.1).\n\n```bash\nmeteor add aldeed:collection2\n```\n\n### 3.x\n\n```bash\nmeteor add aldeed:collection2\nmeteor npm install --save simpl-schema@1.12.3\n```\n\n## Import using static imports\n\nIf you come from a previous version and want to \"keep things as they were\" then this is the option you should choose.\n\n```js\nimport 'meteor/aldeed:collection2/static';\n```\n\n## Import using dynamic imports\n\nDynamic imports helps to cut down on bundle size but it requires you to manually load the package for things to work.\n\n```js\nimport 'meteor/aldeed:collection2/dynamic';\n\nCollection2.load();\n```\n\n\n## Why Use Collection2\n\n- While adding allow/deny rules ensures that only authorized users can edit a document from the client, adding a schema ensures that only acceptable properties and values can be set within that document from the client. Thus, client side inserts and updates can be allowed without compromising security or data integrity.\n- Schema validation for all inserts and updates is reactive, allowing you to easily display customizable validation error messages to the user without any event handling.\n- Schema validation for all inserts and updates is automatic on both the client and the server, providing both speed and security.\n- The [aldeed:autoform](https://github.com/aldeed/meteor-autoform) package can take your collection's schema and automatically create HTML5 forms based on it. AutoForm provides automatic database operations, method calls, validation, and user interface reactivity. You have to write very little markup and no event handling. Refer to the [AutoForm](https://github.com/aldeed/meteor-autoform) documentation for more information.\n\n## Attaching a Schema to a Collection\n\nLet's say we have a normal \"books\" collection, defined in code that runs on both client and server (_common.js_):\n\n```js\nconst Books = new Mongo.Collection('books');\n```\n\nLet's create a `SimpleSchema` schema for this collection. We'll do this in _common.js_, too:\n\n```js\nconst Schemas = {};\n\nSchemas.Book = new SimpleSchema({\n  title: {\n    type: String,\n    label: 'Title',\n    max: 200,\n  },\n  author: {\n    type: String,\n    label: 'Author',\n  },\n  copies: {\n    type: SimpleSchema.Integer,\n    label: 'Number of copies',\n    min: 0,\n  },\n  lastCheckedOut: {\n    type: Date,\n    label: 'Last date this book was checked out',\n    optional: true,\n  },\n  summary: {\n    type: String,\n    label: 'Brief summary',\n    optional: true,\n    max: 1000,\n  },\n});\n```\n\nOnce we have the `SimpleSchema` instance, all we need to do is attach it to our collection using the `attachSchema` method. Again, we will do this in _common.js_:\n\n```js\nBooks.attachSchema(Schemas.Book);\n```\n\nNow that our collection has a schema, we can do a validated insert on either the client or the server:\n\n```js\nBooks.insert({ title: 'Ulysses', author: 'James Joyce' }, (error, result) =\u003e {\n  //The insert will fail, error will be set,\n  //and result will be undefined or false because \"copies\" is required.\n  //\n  //The list of errors is available on `error.invalidKeys` or by calling Books.simpleSchema().namedContext().validationErrors()\n});\n```\n\nOr we can do a validated update:\n\n```js\nBooks.update(book._id, { $unset: { copies: 1 } }, (error, result) =\u003e {\n  //The update will fail, error will be set,\n  //and result will be undefined or false because \"copies\" is required.\n  //\n  //The list of errors is available on `error.invalidKeys` or by calling Books.simpleSchema().namedContext().validationErrors()\n});\n```\n\n### Attaching Multiple Schemas to the Same Collection\n\nNormally, if call `attachSchema` multiple times, the schemas are merged. If you use the `replace: true` option, then it will replace the previously attached schema. However, in some cases you might actually want both schemas attached, with different documents validated against different schemas.\n\nHere is an example:\n\n```js\nProducts.attachSchema(BaseProductSchema);\nProducts.attachSchema(ExtendedProductSchema, {\n  selector: { type: 'extended' },\n});\n```\n\nThis adds support for having a base (default) schema while also using multiple selector schemas.\n\nThere are four behaviors for attaching schemas:\n\n- **Attach schema without selector.** This will extend the base schema and any attached selector schemas.\n- **Attach schema with selector.** If the given selector schema exists, extends the found schema with any new fields. Or add an additional schema that matches the selector only. The new selector schema will first be extended by the base schema, if the base schema is already specified.\n- **Replace schema without selector.** This replaces the base schema and removes any attached selector schemas. If you want to continue to use the original selector schemas on the collection they must be reattached.\n- **Replace schema with selector.** This replaces the schema with the same selector with the new schema fields extended by the base schema, if the base schema is already specified. Othewise adds the new selector schema if it was not found.\n\nIt is possible to use schemas on collections with or without the base schema specified, and with or without selector schemas specified. The selector schemas will always inherit the base schema. Replacing the base schema effectively serves as deleting all schemas off the collection.\n\nHere is another example:\n\n```js\nProducts.attachSchema(SimpleProductSchema, { selector: { type: 'simple' } });\nProducts.attachSchema(VariantProductSchema, { selector: { type: 'variant' } });\n```\n\nNow both schemas are attached. When you insert a document where `type: 'simple'` in the document, it will validate against only the `SimpleProductSchema`. When you insert a document where `type: 'variant'` in the document, it will validate against only the `VariantProductSchema`.\n\nAlternatively, you can pass a `selector` option when inserting to choose which schema to use:\n\n```js\nProducts.insert(\n  { title: 'This is a product' },\n  { selector: { type: 'simple' } }\n);\n```\n\nFor an update or upsert, the matching selector can be in the query, the modifier `$set` object, or the `selector` option.\n\n### attachSchema options\n\n#### transform\n\nIf your validation requires that your doc be transformed using the collection's transform function prior to being validated, then you must pass the `transform: true` option to `attachSchema` when you attach the schema:\n\n```js\nBooks.attachSchema(Schemas.Book, { transform: true });\n```\n\n#### replace\n\nBy default, if a collection already has a schema attached, `attachSchema` will combine the new schema with the existing. Pass the `replace: true` option to `attachSchema` to discard any existing schema.\n\n### Attach a Schema to Meteor.users\n\nObviously, when you attach a schema, you must know what the schema should be. For `Meteor.users`,\nhere is an example schema, which you might have to adjust for your own needs:\n\n```js\nconst Schema = {};\n\nSchema.UserCountry = new SimpleSchema({\n  name: {\n    type: String,\n  },\n  code: {\n    type: String,\n    regEx: /^[A-Z]{2}$/,\n  },\n});\n\nSchema.UserProfile = new SimpleSchema({\n  firstName: {\n    type: String,\n    optional: true,\n  },\n  lastName: {\n    type: String,\n    optional: true,\n  },\n  birthday: {\n    type: Date,\n    optional: true,\n  },\n  gender: {\n    type: String,\n    allowedValues: ['Male', 'Female'],\n    optional: true,\n  },\n  organization: {\n    type: String,\n    optional: true,\n  },\n  website: {\n    type: String,\n    regEx: SimpleSchema.RegEx.Url,\n    optional: true,\n  },\n  bio: {\n    type: String,\n    optional: true,\n  },\n  country: {\n    type: Schema.UserCountry,\n    optional: true,\n  },\n});\n\nSchema.User = new SimpleSchema({\n  username: {\n    type: String,\n    // For accounts-password, either emails or username is required, but not both. It is OK to make this\n    // optional here because the accounts-password package does its own validation.\n    // Third-party login packages may not require either. Adjust this schema as necessary for your usage.\n    optional: true,\n  },\n  emails: {\n    type: Array,\n    // For accounts-password, either emails or username is required, but not both. It is OK to make this\n    // optional here because the accounts-password package does its own validation.\n    // Third-party login packages may not require either. Adjust this schema as necessary for your usage.\n    optional: true,\n  },\n  'emails.$': {\n    type: Object,\n  },\n  'emails.$.address': {\n    type: String,\n    regEx: SimpleSchema.RegEx.Email,\n  },\n  'emails.$.verified': {\n    type: Boolean,\n  },\n  // Use this registered_emails field if you are using splendido:meteor-accounts-emails-field / splendido:meteor-accounts-meld\n  registered_emails: {\n    type: Array,\n    optional: true,\n  },\n  'registered_emails.$': {\n    type: Object,\n    blackbox: true,\n  },\n  createdAt: {\n    type: Date,\n  },\n  profile: {\n    type: Schema.UserProfile,\n    optional: true,\n  },\n  // Make sure this services field is in your schema if you're using any of the accounts packages\n  services: {\n    type: Object,\n    optional: true,\n    blackbox: true,\n  },\n  // DISCLAIMER: This only applies to the first and second version of meteor-roles package.\n  // https://github.com/Meteor-Community-Packages/meteor-collection2/issues/399\n  // Add `roles` to your schema if you use the meteor-roles package.\n  // Option 1: Object type\n  // If you specify that type as Object, you must also specify the\n  // `Roles.GLOBAL_GROUP` group whenever you add a user to a role.\n  // Example:\n  // Roles.addUsersToRoles(userId, [\"admin\"], Roles.GLOBAL_GROUP);\n  // You can't mix and match adding with and without a group since\n  // you will fail validation in some cases.\n  roles: {\n    type: Object,\n    optional: true,\n    blackbox: true,\n  },\n  // Option 2: [String] type\n  // If you are sure you will never need to use role groups, then\n  // you can specify [String] as the type\n  roles: {\n    type: Array,\n    optional: true,\n  },\n  'roles.$': {\n    type: String,\n  },\n  // In order to avoid an 'Exception in setInterval callback' from Meteor\n  heartbeat: {\n    type: Date,\n    optional: true,\n  },\n});\n\nMeteor.users.attachSchema(Schema.User);\n```\n\nThis schema has not been thoroughly vetted to ensure\nthat it accounts for all possible properties the accounts packages might try to set. Furthermore,\nany other packages you add might also try to set additional properties. If you see warnings in the\nconsole about keys being removed, that's a good indication that you should add those keys to the\nschema.\n\nNote also that this schema uses the `blackbox: true` option for simplicity. You might choose instead\nto figure out a more specific schema.\n\n(If you figure out a more accurate `Meteor.users` schema, documentation pull requests are welcome.)\n\n## Schema Format\n\nRefer to the\n[simpl-schema](https://github.com/aldeed/simple-schema-js) package\ndocumentation for a list of all the available schema rules and validation\nmethods.\n\nUse the `MyCollection.simpleSchema()` method to access the attached `SimpleSchema`\ninstance for a Mongo.Collection instance. For example:\n\n```js\nMyCollection.simpleSchema().validate(doc);\n```\n\n## Passing Options\n\nIn Meteor, the `update` function accepts an options argument. Collection2 changes the `insert` function signature to also accept options in the same way, as an optional second argument. Whenever this documentation says to \"use X option\", it's referring to this options argument. For example:\n\n```js\nmyCollection.insert(doc, { validate: false });\n```\n\n## Validation Contexts\n\nIn the examples above, note that we called `namedContext()` with no arguments\nto access the SimpleSchema reactive validation methods. Contexts let you keep\nmultiple separate lists of invalid keys for a single collection.\nIn practice you might be able to get away with always using the default context.\nIt depends on what you're doing. If you're using the context's reactive methods\nto update UI elements, you might find the need to use multiple contexts. For example,\nyou might want one context for inserts and one for updates, or you might want\na different context for each form on a page.\n\nTo use a specific named validation context, use the `validationContext` option\nwhen calling `insert` or `update`:\n\n```js\nBooks.insert(\n  { title: 'Ulysses', author: 'James Joyce' },\n  { validationContext: 'insertForm' },\n  (error, result) =\u003e {\n    //The list of errors is available by calling Books.simpleSchema().namedContext(\"insertForm\").validationErrors()\n  }\n);\n\nBooks.update(\n  book._id,\n  { $unset: { copies: 1 } },\n  { validationContext: 'updateForm' },\n  (error, result) =\u003e {\n    //The list of errors is available by calling Books.simpleSchema().namedContext(\"updateForm\").validationErrors()\n  }\n);\n```\n\n## Validating Without Inserting or Updating\n\nIt's also possible to validate a document without performing the actual insert or update:\n\n```js\nBooks.simpleSchema()\n  .namedContext()\n  .validate({ title: 'Ulysses', author: 'James Joyce' }, { modifier: false });\n```\n\nSet the modifier option to true if the document is a mongo modifier object.\n\nYou can also validate just one key in the document:\n\n```js\nBooks.simpleSchema()\n  .namedContext()\n  .validate(\n    { title: 'Ulysses', author: 'James Joyce' },\n    { modifier: false, keys: ['title'] }\n  );\n```\n\nOr you can specify a certain validation context when calling either method:\n\n```js\nBooks.simpleSchema()\n  .namedContext('insertForm')\n  .validate({ title: 'Ulysses', author: 'James Joyce' }, { modifier: false });\nBooks.simpleSchema()\n  .namedContext('insertForm')\n  .validate(\n    { title: 'Ulysses', author: 'James Joyce' },\n    { modifier: false, keys: ['title'] }\n  );\n```\n\nRefer to the [simpl-schema](https://github.com/aldeed/simple-schema-js) package documentation for more information about these methods.\n\n## Inserting or Updating Without Validating\n\nTo skip validation, use the `validate: false` option when calling `insert` or\n`update`. On the client (untrusted code), this will skip only client-side\nvalidation. On the server (trusted code), it will skip all validation. The object is still cleaned and autoValues are still generated.\n\n## Inserting or Updating Without Cleaning\n\n### Skip removing properties that are not in the schema\n\nTo skip object property filtering, set the `filter` option to `false` when you call `insert` or `update`.\n\n### Skip conversion of values to match what schema expects\n\nTo skip automatic value conversion, set the `autoConvert` option to `false` when you call `insert` or `update`.\n\n### Skip removing empty strings\n\nTo skip removing empty strings, set the `removeEmptyStrings` option to `false` when you call `insert` or `update`.\n\n### Skip generating automatic values\n\nTo skip adding automatic values, set the `getAutoValues` option to `false` when you call `insert` or `update`. This works only in server code.\n\n### Pick or omit from the attached schema\n\nTo pick or omit fields from the schema for the operation, set the 'pick' or 'omit' option respectively to an array of schema field names. These options are mutually exclusive, so you cannot have both present in the options object at the same time.\n\nThis is the implementation of [pick and omit functionality from simple-schema](https://github.com/aldeed/simpl-schema#extracting-schemas), but on your DB calls like this:\n\n```js\n// Will insert everything except 'noop'\ncollection.insert(\n  { foo: 'foo', noop: 'nooooo', bar: 'whiskey' },\n  { omit: ['noop'] }\n);\n```\n\n```js\n// Pick only 'foo'\ncollection.update(\n  { _id: 'myid' },\n  { $set: { foo: 'test', bar: 'changed' } },\n  { pick: ['foo'] }\n);\n```\n\n## Inserting or Updating Bypassing Collection2 Entirely\n\nEven if you skip all validation and cleaning, Collection2 will still do some object parsing that can take a long time for a large document. To bypass this, set the `bypassCollection2` option to `true` when you call `insert` or `update`. This works only in server code.\n\n## Additional SimpleSchema Options\n\nIn addition to all the other schema validation options documented in the\n[simpl-schema](https://github.com/longshotlabs/simpl-schema) package, the\ncollection2 package adds additional options explained in this section.\n\n### index and unique\n\nSee https://github.com/aldeed/meteor-schema-index\n\n### denyInsert and denyUpdate\n\nSee https://github.com/aldeed/meteor-schema-deny\n\n### autoValue\n\nThe `autoValue` option is provided by the SimpleSchema package and is documented\nthere. Collection2 adds the following properties to `this` for any `autoValue`\nfunction that is called as part of a C2 database operation:\n\n- isInsert: True if it's an insert operation\n- isUpdate: True if it's an update operation\n- isUpsert: True if it's an upsert operation (either `upsert()` or `upsert: true`)\n- userId: The ID of the currently logged in user. (Always `null` for server-initiated actions.)\n- isFromTrustedCode: True if the insert, update, or upsert was initiated from trusted (server) code\n- docId: The `_id` property of the document being inserted or updated. For an insert, this will be set only when it is provided in the insert doc, or when the operation is initiated on the client. For an update or upsert, this will be set only when the selector is or includes the `_id`, or when the operation is initiated on the client.\n\nNote that autoValue functions are run on the client only for validation purposes,\nbut the actual value saved will always be generated on the server, regardless of\nwhether the insert/update is initiated from the client or from the server.\n\nThere are many possible use cases for `autoValue`. It's probably easiest to\nexplain by way of several examples:\n\n```js\n{\n  // Force value to be current date (on server) upon insert\n  // and prevent updates thereafter.\n  createdAt: {\n    type: Date,\n    autoValue: function() {\n      if (this.isInsert) {\n        return new Date();\n      } else if (this.isUpsert) {\n        return {$setOnInsert: new Date()};\n      } else {\n        this.unset();  // Prevent user from supplying their own value\n      }\n    }\n  },\n  // Force value to be current date (on server) upon update\n  // and don't allow it to be set upon insert.\n  updatedAt: {\n    type: Date,\n    autoValue: function() {\n      if (this.isUpdate) {\n        return new Date();\n      }\n    },\n    denyInsert: true,\n    optional: true\n  },\n  // Whenever the \"content\" field is updated, automatically store\n  // the first word of the content into the \"firstWord\" field.\n  firstWord: {\n    type: String,\n    optional: true,\n    autoValue: function() {\n      var content = this.field(\"content\");\n      if (content.isSet) {\n        return content.value.split(' ')[0];\n      } else {\n        this.unset();\n      }\n    }\n  },\n  // Whenever the \"content\" field is updated, automatically\n  // update a history array.\n  updatesHistory: {\n    type: Array,\n    optional: true,\n    autoValue: function() {\n      var content = this.field(\"content\");\n      if (content.isSet) {\n        if (this.isInsert) {\n          return [{\n              date: new Date(),\n              content: content.value\n            }];\n        } else {\n          return {\n            $push: {\n              date: new Date,\n              content: content.value\n            }\n          };\n        }\n      } else {\n        this.unset();\n      }\n    }\n  },\n  'updatesHistory.$': {\n    type: Object,\n  },\n  'updatesHistory.$.date': {\n    type: Date,\n    optional: true\n  },\n  'updatesHistory.$.content': {\n    type: String,\n    optional: true\n  },\n  // Automatically set HTML content based on markdown content\n  // whenever the markdown content is set.\n  htmlContent: {\n    type: String,\n    optional: true,\n    autoValue: function(doc) {\n      var markdownContent = this.field(\"markdownContent\");\n      if (Meteor.isServer \u0026\u0026 markdownContent.isSet) {\n        return MarkdownToHTML(markdownContent.value);\n      }\n    }\n  }\n}\n```\n\n### custom\n\nThe `custom` option is provided by the SimpleSchema package and is documented\nthere. Collection2 adds the following properties to `this` for any `custom`\nfunction that is called as part of a C2 database operation:\n\n- isInsert: True if it's an insert operation\n- isUpdate: True if it's an update operation\n- isUpsert: True if it's an upsert operation (either `upsert()` or `upsert: true`)\n- userId: The ID of the currently logged in user. (Always `null` for server-initiated actions.)\n- isFromTrustedCode: True if the insert, update, or upsert was initiated from trusted (server) code\n- docId: The `_id` property of the document being inserted or updated. For an insert, this will be set only when it is provided in the insert doc, or when the operation is initiated on the client. For an update or upsert, this will be set only when the selector is or includes the `_id`, or when the operation is initiated on the client.\n\n## What Happens When The Document Is Invalid?\n\nThe callback you specify as the last argument of your `insert()` or `update()` call will have the first argument (`error`) set to an `Error` instance. The error message for the first invalid key is set in the `error.message`, and the full `validationErrors` array is available on `error.invalidKeys`. This is true on both client and server, even if validation for a client-initiated operation does not fail until checked on the server.\n\nIf you attempt a synchronous operation in server code, the same validation error is thrown since there is no callback to pass it to. If this happens in a server method (defined with `Meteor.methods`), a more generic `Meteor.Error` is passed to your callback back on the client. This error does not have an `invalidKeys` property, but it does have the error message for the first invalid key set in `error.reason`.\n\nGenerally speaking, you would probably not use the `Error` for displaying to the user. You can instead use the reactive methods provided by the SimpleSchema validation context to display the specific error messages to the user somewhere in the UI. The [autoform](https://github.com/aldeed/meteor-autoform) package provides some UI components and helpers for this purpose.\n\n## More Details\n\nFor the curious, this is exactly what Collection2 does before every insert or update:\n\n1. Removes properties from your document or mongo modifier object if they are not explicitly listed in the schema. (To skip this, set the `filter` option to `false` when you call `insert` or `update`.)\n1. Automatically converts some properties to match what the schema expects, if possible. (To skip this, set the `autoConvert` option to `false` when you call `insert` or `update`.)\n1. Optimizes your operation so that empty string values will not be stored. (To skip this, set the `removeEmptyStrings` option to `false` when you call `insert` or `update`.)\n1. Adds automatic (forced or default) values based on your schema. Values are added only on the server and will make their way back to your client when your subscription is updated. (To skip this in server code, set the `getAutoValues` option to `false` when you call `insert` or `update`.)\n1. Validates your document or mongo modifier object. (To skip this, set the `validate` option to `false` when you call `insert` or `update`.)\n1. Performs the insert or update like normal, only if it was valid.\n\nCollection2 is simply calling SimpleSchema methods to do these things. The validation happens on both the client and the server for client-initiated actions, giving you the speed of client-side validation along with the security of server-side validation.\n\n## Community Add-On Packages\n\n### Automatic Migrations\n\nThe [davidyaha:collection2-migrations](https://atmospherejs.com/davidyaha/collection2-migrations) package can watch for schema changes between server restarts and perform some automatic data migration and cleanup.\n\n## Problems\n\nYou might find yourself in a situation where it seems as though validation is not working correctly. First, you should enable SimpleSchema debug mode by setting `SimpleSchema.debug = true`, which may log some additional information. If you're still confused, read through the following tricky, confusing situations.\n\n### SubObjects and Arrays of Objects\n\nOne critical thing to know about Collection2 and SimpleSchema is that they don't validate the _saved document_ but rather the _proposed insert doc_ or the _update modifier_. In the case of updates, this means there is some information unknown to SimpleSchema, such as whether the array object you're attempting to modify already exists or not. If it doesn't exist, MongoDB would create it, so SimpleSchema will validate conservatively. It will assume that any properties not set by the modifier will not exist after the update. This means that the modifier will be deemed invalid if any required keys in the same object are not explicitly set in the update modifier.\n\nFor example, say we add the following keys to our \"books\" schema:\n\n```js\n{\n    borrowedBy: {\n        type: Array\n    },\n    'borrowedBy.$': {\n        type: Object\n    },\n    \"borrowedBy.$.name\": {\n        type: String\n    },\n    \"borrowedBy.$.email\": {\n        type: String,\n        regEx: SimpleSchema.RegEx.Email\n    },\n}\n```\n\nEvery object in the `borrowedBy` array must have a `name` and `email` property.\n\nNow we discover that the name is incorrect in item 1, although the email address is correct. So we will just set the name to the correct value:\n\n```js\nBooks.update(id, { $set: { 'borrowedBy.1.name': 'Frank' } });\n```\n\nHowever, this will not pass validation. Why? Because we don't know whether item 1 in the `borrowedBy` array already exists, so we don't know whether it will have the required `email` property after the update finishes.\n\nThere are three ways to make this work:\n\n- `$set` the entire object\n- `$set` all required keys in the object\n- Perform the update on the server, and pass the `validate: false` option to skip validation.\n\nWhen this situation occurs on the client with an `autoForm`, it generally does not cause any problems because AutoForm is smart enough to `$set` the entire object; it's aware of this potential issue. However, this means that you need to ensure that all required properties are represented by an `input` on the form. In our example, if you want an `autoForm` that only shows a field for changing the borrowedBy `name` and not the `email`, you should include both fields but make the `email` field hidden. Alternatively, you can submit the `autoForm` to a server method and then do a server update without validation.\n\nAlthough these examples focused on an array of objects, sub-objects are treated basically the same way.\n\n## Disable displaying collection name in error message\nSince version `3.4` an option has been added that disables displaying of collection names in error messages. This is set to `false` until version `4.0`. You can change this by setting the value in your Meteor settings like this:\n```json\n{\n  \"packages\": {\n    \"collection2\": {\n      \"disableCollectionNamesInValidation\": true\n    }\n  }\n}\n```\n\n## Contributors\n\nThis project exists thanks to all the people who contribute. [[Contribute]](CONTRIBUTING.md).\n\u003ca href=\"graphs/contributors\"\u003e\u003cimg src=\"https://opencollective.com/meteor-collection2/contributors.svg?width=890\" /\u003e\u003c/a\u003e\n\n### Major Code Contributors\n\n@aldeed\n@mquandalle\n@newsiberian\n@harryadel\n@StorytellerCZ\n@SimonSimCity\n\n(Add yourself if you should be listed here.)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMeteor-Community-Packages%2Fmeteor-collection2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMeteor-Community-Packages%2Fmeteor-collection2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMeteor-Community-Packages%2Fmeteor-collection2/lists"}