{"id":103514,"date":"2024-09-13T20:39:26","date_gmt":"2024-09-13T20:39:26","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=103514"},"modified":"2026-09-25T08:38:55","modified_gmt":"2026-09-25T08:38:55","slug":"working-with-schema-validation-in-mongodb","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/nosql\/mongodb\/working-with-schema-validation-in-mongodb\/","title":{"rendered":"MongoDB schema validation guide: handling existing documents"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><strong>MongoDB doesn&#8217;t retroactively apply new schema validation rules to documents that already exist in a collection, so adding rules can leave invalid documents sitting alongside valid ones. <\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>This article, the second on schema validation within <a href=\"https:\/\/www.red-gate.com\/simple-talk\/collections\/robert-sheldon-ongoing-mongodb-primer\/\" target=\"_blank\" rel=\"noreferrer noopener\">this MongoDB series<\/a>, covers how to find those invalid documents with the <code>$nor<\/code> operator, deliberately bypass validation with <code>bypassDocumentValidation<\/code>, update and delete invalid documents, and control validation strictness with the <code>validationAction<\/code> and <code>validationLevel<\/code> options.<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The examples in this article demonstrate various concepts for working with schema validation, as it applies to existing documents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I show you how to find documents that conform and don\u2019t conform to the validation rules, as well as how to bypass schema validation when inserting or updating a document. I also show you how to update and delete invalid documents in a collection. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, I explain how you can use validation options to override the default schema validation behavior when inserting and updating documents.<\/p>\n\n\n\n<div id=\"callout-block_39bab4868e9bedead5ae94920828d349\" class=\"callout alignnone\">\n    <div class=\"child-last:mb-0 child-first:mt-0 bg-gray-50 dark:bg-gray-950 p-4xl my-3xl\">\n\n<p class=\"wp-block-paragraph\"><strong>The complete guide to MongoDB, from beginner to expert<\/strong> &#8211; <a href=\"https:\/\/www.red-gate.com\/simple-talk\/collections\/robert-sheldon-ongoing-mongodb-primer\/\" target=\"_blank\" rel=\"noreferrer noopener\">click here<\/a> for the full series.<\/p>\n\n<\/div>\n<\/div> \n\n\n<p class=\"wp-block-paragraph\"><em>Note: For the examples in this article, I used the same MongoDB Atlas and MongoDB Compass environments I used for the previous articles in this series. Refer to the first article for details about setting up these environments. Because this article builds off the previous article, I\u2019ve also used the same <code>hr<\/code> database and <code>candidates<\/code> collection for the examples. If you\u2019ve already deleted the database and collection, you can simply re-create them. The goal is to start with an empty collection with no validation rules defined.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-to-search-for-invalid-documents-in-a-mongodb-collection\">How to search for invalid documents in a MongoDB collection<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When you define schema validation rules on a collection that already contains documents, some of those documents might not adhere to the new rules. In which case, you might want to search your collection to determine which documents conform to the rules and which ones do not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this section, I demonstrate how to find valid and invalid documents. If you want to try out the examples, you should create the <code>hr<\/code> database and <code>candidates<\/code> collection, if they don\u2019t already exist.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The examples in this article were developed for MongoDB Shell. You can use the version of Shell integrated into MongoDB Compass, or you can use the version available through your system\u2019s command-line utility. I like using the version in Compass because I can quickly review my inserted and updated documents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If your collection contains any documents, delete those and then delete any validation rules. To remove validation rules, open MongoDB Shell, switch to the <code>hr<\/code> database, and run the following <code>runCommand<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.runCommand( { collMod: \"candidates\", validator: {} } );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>runCommand<\/code> method calls the <code>collMod<\/code> database command, which lets you modify options on the specified collection. In this case, the command calls the <code>validator<\/code> method, just like you saw in the previous article when defining validation rules. This time, however, the method\u2019s argument is an empty document (curly brackets), which means that no rules will be defined. If rules already exist, they will be removed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you run this statement, you should receive an OK message that indicates the statement successfully executed. Of course, you could have dropped and re-created the collection, rather than deleting the documents and schema rules. It\u2019s up to you which approach you take, although it can be useful to know how to remove validation rules.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once you have a clean slate, you should run the following <code>insertMany<\/code> statement, which adds four simple documents to the <code>candidates<\/code> collection:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.insertMany([\n  { _id: 101,\n    \"name\": \"Drew\", \n    \"dob\": \"1973-9-12\" },\n  { _id: 102,\n    \"name\": \"Parker\", \n    \"dob\": new Date(\"1982-12-2\") },\n  { _id: 103,\n    \"name\": \"Harper\", \n    \"dob\": \"1967-3-25\" },\n  { _id: 104,\n    \"name\": \"Darcy\", \n    \"dob\": new Date(\"1999-5-18\") }\n]);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>dob<\/code> values in these documents are intentionally defined with different data types\u2014two as <code>String<\/code> values and two as <code>Date<\/code> values. The difference in types will help to demonstrate how to find valid and invalid documents, as you\u2019ll see shortly. When you run the <code>insertMany<\/code> statement, it should return the following results, which indicate that the documents have been added to the collection:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  acknowledged: true,\n  insertedIds: {\n    '0': 101,\n    '1': 102,\n    '2': 103,\n    '3': 104\n  }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After you add the documents, you can run the following <code>runCommand<\/code> statement to define a simple set of schema validation rules:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.runCommand( { collMod: \"candidates\",\n  validator: {\n    $jsonSchema: {\n      bsonType: \"object\",\n      required: [ \"name\", \"dob\" ],\n      properties: {\n        \"name\": { bsonType: \"string\" },\n        \"dob\": { bsonType: \"date\" }\n      }\n    }\n  }\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement calls the <code>validator<\/code> method, which in turn calls the <code>$jsonSchema<\/code> operator. The operator defines a JSON Schema object that contains the validation rules. Notice that the <code>properties<\/code> element specifies that the <code>dob<\/code> field must be the <code>date<\/code> type. The rest of the statement\u2019s components work just like you saw in the previous article. If you have any questions about what I\u2019ve done here, refer to that article.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Although the documents and validation rules that we\u2019ve added to the collection are relatively simple, they are enough to demonstrate how to find valid and invalid documents. The same principles apply no matter how complex your documents or validation rules.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When working with a collection\u2019s schema validation, there might be times when you want to view or retrieve the validation rules themselves. For this, you can use the <code>getCollectionInfos<\/code> database method, specifying the <code>validator<\/code> option, as shown in the following statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.getCollectionInfos( \n  { name: \"candidates\" } )[0].options.validator;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>getCollectionInfos<\/code> method lets you view different options about the specified collection, in this case, <code>candidates<\/code>. To retrieve the validation rules, you must specify the <code>validator<\/code> option as it is constructed here. The statement should return the following <code>$jsonSchema<\/code> object:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  '$jsonSchema': {\n    bsonType: 'object',\n    required: [ 'name', 'dob' ],\n    properties: { name: { bsonType: 'string' }, dob: { bsonType: 'date' } }\n  }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Together, the <code>runCommand<\/code> method and <code>validator<\/code> option make it easy to retrieve a collection\u2019s validation rules so you can see how they\u2019ve been defined. You can also use this approach to find valid and nonvalid documents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To search for valid documents, you need to include the JSON Schema object as an argument to the <code>find<\/code> collection method. A good way to do this is to assign the object to a variable and then pass the variable in as an argument to the <code>find<\/code> method. For example, the following <code>let<\/code> statement assigns the JSON Schema object returned by the <code>getCollectionInfos<\/code> method to the <code>schema1<\/code> variable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">let schema1 = \n  db.getCollectionInfos( \n    { name: \"candidates\" } )[0].options.validator;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After you define the variable, you can pass it into the <code>find<\/code> statements that you run within the same MongoDB Shell session. Before I demonstrate how to do this, however, I want to first show you how to assign the JSON Schema object definition directly to the variable, without using the <code>getCollectionInfos<\/code> method. In this way, you can check for valid and invalid documents before you define validation rules on a collection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To assign the JSON Schema object directly to the variable, use the <code>$jsonSchema<\/code> operator to define the object, using this as the variable value:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">let schema1 =\n{\n  $jsonSchema: {\n    bsonType: \"object\",\n    required: [ \"name\", \"dob\" ],\n    properties: {\n      \"name\": { bsonType: \"string\" },\n      \"dob\": { bsonType: \"date\" }\n    }\n  }\n};<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Regardless of which approach you use to define your variable, you can easily verify its contents by running the following <code>print<\/code> command:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">print(schema1);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The command should return the <code>$jsonSchema<\/code> object, as shown in the following results:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  '$jsonSchema': {\n    bsonType: 'object',\n    required: [ 'name', 'dob' ],\n    properties: { name: [Object], dob: [Object] }\n  }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After you define the <code>schema1<\/code> variable you can use it in your <code>find<\/code> statements to search for valid and invalid documents. For example, the following <code>find<\/code> statement searches the <code>candidates<\/code> collection for documents that conform to the JSON Schema object in the <code>schema1<\/code> variable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.find( schema1 );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement returns the following results, which include the documents with the <code>_id<\/code> values of <code>102<\/code> and <code>104<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  _id: 102,\n  name: 'Parker',\n  dob: 1982-12-02T08:00:00.000Z\n}\n{\n  _id: 104,\n  name: 'Darcy',\n  dob: 2003-07-02T07:00:00.000Z\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you want to search for the documents that do not conform to the validation rules, you can use the <code>$nor<\/code> logical operator, along with the <code>schema1<\/code> variable:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.find( { $nor: [ schema1 ] } );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This time, the <code>find<\/code> statement returns only the invalid documents, which include the documents with the <code>_id<\/code> values of <code>101<\/code> and <code>103<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  _id: 101,\n  name: 'Drew',\n  dob: '1973-9-12'\n}\n{\n  _id: 103,\n  name: 'Harper',\n  dob: '1967-3-25'\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you can see, the value for the <code>dob<\/code> field in the results is a <code>String<\/code> value in both cases, which violates the validation rules. The field must take a <code>Date<\/code> value to conform to the rules. Except for this issue, the documents conform to the validation rules in all other ways.<\/p>\n\n\n\n<section id=\"my-first-block-block_9890b7902a1ed30adc0dffca43f92cee\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Simple Talk is brought to you by Redgate Software<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            Take control of your databases with the trusted Database DevOps solutions provider. Automate with confidence, scale securely, and unlock growth through AI.                                    <\/div>\n            <\/div>\n                                            <a href=\"https:\/\/www.red-gate.com\/solutions\/overview\/\" class=\"btn btn--secondary btn--lg\" aria-label=\"Discover how Redgate can help you: Simple Talk is brought to you by Redgate Software\">Discover how Redgate can help you<\/a>\n                    <\/div>\n    <\/div>\n<\/section>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-to-bypass-schema-validation-in-a-mongodb-collection\">How to bypass schema validation in a MongoDB collection<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">At times, you might want to add a document to a collection that violates the validation rules. For example, you might need to restore data from an archive file that includes invalid documents, which you want to preserve them in their original state.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As you saw in the previous article, MongoDB will return an error when you try to insert a document that violates the validation rules. For instance, MongoDB returns an error if you try to run the following <code>insertOne<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.insertOne(\n  {\n    _id: 105,\n    \"name\": \"Carey\", \n    \"dob\": \"2003-7-2\"\n  }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement attempts to insert a document whose <code>dob<\/code> field is a <code>String<\/code> value, which violates the schema we defined above. However, you can override this behavior by including the <code>bypassDocumentValidation<\/code> option in your <code>insertOne<\/code> statement, as in the following example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.insertOne(\n  {\n    _id: 105,\n    \"name\": \"Carey\", \n    \"dob\": \"2003-7-2\"\n  },\n  { bypassDocumentValidation: true }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>bypassDocumentValidation<\/code> option takes a Boolean as its value. When the option is set to <code>true<\/code>, MongoDB ignores the validation rules and inserts the document into the collection. The option works the same way for an <code>insertMany<\/code> statement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When you include the <code>bypassDocumentValidation<\/code> option in an <code>insertOne<\/code> or <code>insertMany<\/code> statement, the option applies only when you run the statement. Once you insert the document into the collection, you cannot update it in a way the violates the validation rules. For example, if you try to run the following <code>updateOne<\/code> statement, MongoDB will return an error message stating that the document failed validation:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateOne(\n  { _id : 105 },\n  { $set: { \"dob\" : \"2003-7-3\" } }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">However, the <code>updateOne<\/code> method, as well as the <code>updateMany<\/code> method, also support the <code>bypassDocumentValidation<\/code> option, as in the following example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateOne(\n  { _id : 105 },\n  { $set: { \"dob\" : \"2003-7-3\" } },\n  { bypassDocumentValidation: true }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When you run this statement, MongoDB ignores the validation rules, updates the document, and returns a message indicating that one document has been modified.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As with inserting data, the <code>bypassDocumentValidation<\/code> option applies only to the <code>updateOne<\/code> or <code>updateMany<\/code> statements when you run them. If you later try to update the statement, it must once again conform to the validation rules or include the <code>bypassDocumentValidation<\/code> option.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-to-update-invalid-documents-in-a-mongodb-collection\">How to update invalid documents in a MongoDB collection<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">By default, MongoDB applies validation rules whenever you try to insert or update a document, unless you include the <code>bypassDocumentValidation<\/code> option in your statements. However, MongoDB does not apply those rules to the documents that already exist in the collection at the time you define the validation rules, which means your collection could contain invalid documents.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In some cases, you might want to update the invalid documents to bring them into conformance with the validation rules or to mark them in some way as being invalid. Before you update the documents, however, you can first search for them so you can assess what you have. For this, you can again use the <code>find<\/code> method, along with the <code>$nor<\/code> operator and JSON Schema object variable.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can use the <code>schema1<\/code> variable you defined earlier as long you\u2019re working in the same user session. If you\u2019ve reconnected to MongoDB since running those earlier statements, you\u2019ll need to redefine the variable before you can use it, in which case, you should again run the following <code>let<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">let schema1 = \n  db.getCollectionInfos( \n    { name: \"candidates\" } )[0].options.validator;<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Once you\u2019ve defined the variable, you can then run your <code>find<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.find( { $nor: [ schema1 ] } );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement returns the following results, which indicate that the <code>candidates<\/code> collection contains three invalid documents:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">{\n  _id: 101,\n  name: 'Drew',\n  dob: '1973-9-12'\n}\n{\n  _id: 103,\n  name: 'Harper',\n  dob: '1967-3-25'\n}\n{\n  _id: 105,\n  name: 'Carey',\n  dob: '2003-7-3'\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">To update the invalid documents, you can use <code>$nor<\/code> operator and <code>schema1<\/code> variable within an <code>updateMany<\/code> statement as part of the statement\u2019s filter. For example, the following <code>updateMany<\/code> statement uses the operator and variable to change the <code>dob<\/code> field in the invalid documents:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateMany(\n  { $nor: [ schema1 ] },\n  [ { $set: { \"dob\": { $toDate: \"$dob\" } } } ]\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement first searches for the invalid documents\u2014using the <code>$nor<\/code> operator and the <code>schema1<\/code> variable\u2014and then uses the <code>$toDate<\/code> method to set the field\u2019s data type to <code>Date<\/code>. When you run the statement, you should receive a message indicating that the three documents were modified. If you were to examine the documents, you would find that the <code>dob<\/code> field in each document is now defined with the <code>Date<\/code> data type.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this case, the <code>updateMany<\/code> statement modifies all invalid documents because it assumes that the <code>dob<\/code> value needs to be updated in every one of those documents. However, there might be times when you need to refine your statement\u2019s filter to target only a subset of the invalid documents, as in the following example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateMany(\n  { $nor: [ schema1 ], \"dob\": { $type : \"string\" } },\n  [ { $set: { \"dob\": { $toDate: \"$dob\" } } } ]\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This time, the <code>updateMany<\/code> statement looks for documents that are invalid documents <em>and<\/em> whose <code>dob<\/code> field has a <code>String<\/code> value. If there are documents that violate the validation rules in other ways, they will not be updated.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-to-delete-invalid-documents-in-a-mongodb-collection\">How to delete invalid documents in a MongoDB collection<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You can use the same logic\u2014the <code>$nor<\/code> operator and <code>schema1<\/code> variable\u2014when deleting invalid documents. For example, suppose you insert the following document into the <code>candidates<\/code> collection:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.insertOne(\n  {\n    _id: 106,\n    \"name\": \"Avery\", \n    \"dob\": \"1993-11-24\"\n  },\n  { bypassDocumentValidation: true }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Notice that the document includes the <code>bypassDocumentValidation<\/code> option, allowing the document to be added even if it violates the validation rules, which it does.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">After you insert the document, you might decide to delete it, along with any other invalid documents in the collection. For this, you can use a <code>deleteMany<\/code> statement, once again incorporating the <code>$nor<\/code> operator and <code>schema1<\/code> variable, as in the following example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.deleteMany( { $nor: [ schema1 ] } );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When you run the statement, MongoDB should return a message indicating that one document has been deleted (assuming you\u2019ve been following along with the examples). You can verify the deletion by running the following <code>find<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.find( { $nor: [ schema1 ] } );<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The statement should now return no results because the <code>candidates<\/code> collection no longer contains invalid documents. At this point, the collection should include only five documents, all of them in conformance with the validation rules. In other words, the <code>dob<\/code> field in each document is now defined with the <code>Date<\/code> data type.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-how-to-set-the-schema-validation-action-and-level-in-mongodb\">How to set the schema validation action and level in MongoDB<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The examples in this article, as well as those in the previous article, demonstrated how validation rules can affect your insert and update operations. As you have seen, you can insert documents only if they conform to those rules, unless you specify the <code>bypassDocumentValidation<\/code> option. Likewise, you can update documents only if the updated documents will conform to the rules.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, this is only the default behavior. You can actually control how inserts and updates are handled when defining your validation rules. To implement these controls, you must include one or both of the following options when defining your validation rules:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><code><strong>validationAction.<\/strong><\/code> Determines whether MongoDB generates an error or warning when a document violates the validation rules. If the option is set to <code>error<\/code> (the default), MongoDB rejects the inserted or updated document and issues an error. If the option is set to <code>warn<\/code>, MongoDB permits the document to be inserted or updated, but records the violation in the MongoDB log.<\/li>\n\n\n\n<li><code><strong>validationLevel.<\/strong><\/code> Determines how MongoDB should apply the validation rules. If the option is set to <code>strict<\/code> (the default), MongoDB applies the rules to all inserted and updated documents. If the option is set to <code>moderate<\/code>, MongoDB applies the rules to all inserted documents but only to updates in which the document being updated is already valid. If the document is invalid, MongoDB does not enforce the validation rules during the update.<\/li>\n<\/ul>\n<\/div>\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s take a look at a few examples to better understand how these options work. If you want to try them out for yourself, first run the following statements, which delete all the documents, removes the validation rules, and adds the original documents back into the collection:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.deleteMany({});\ndb.runCommand( { collMod: \"candidates\", validator: {} } );\ndb.candidates.insertMany([\n  { _id: 101,\n    \"name\": \"Drew\", \n    \"dob\": \"1973-9-12\" },\n  { _id: 102,\n    \"name\": \"Parker\", \n    \"dob\": new Date(\"1982-12-2\") },\n  { _id: 103,\n    \"name\": \"Harper\", \n    \"dob\": \"1967-3-25\" },\n  { _id: 104,\n    \"name\": \"Darcy\", \n    \"dob\": new Date(\"1999-5-18\") }\n]);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The next step is the define the validation rules, once again using a <code>runCommand<\/code> statement. This time, however, you should include the <code>validationAction<\/code> and <code>validationLevel<\/code> options in your <code>collMod<\/code> command, as in the following example:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.runCommand( { collMod: \"candidates\",\n  validator: {\n    $jsonSchema: {\n      bsonType: \"object\",\n      required: [ \"name\", \"dob\" ],\n      properties: {\n        \"name\": { bsonType: \"string\" },\n        \"dob\": { bsonType: \"date\" }\n      }\n    }\n  },\n  validationAction: \"warn\",\n  validationLevel: \"strict\"\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>runCommand<\/code> statement defines the same validation rules we\u2019ve been using throughout this article, but it also includes the two validation options. The <code>validationLevel<\/code> option is set to its default value, <code>strict<\/code>, so nothing has changed there, but the <code>validationAction<\/code> option is set to <code>warn<\/code>, which changes MongoDB\u2019s default behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We can test this change by trying to insert a document into the <code>candidates<\/code> collection. The following <code>insertOne<\/code> statement attempts to add an invalid document to the collection, without including the <code>bypassDocumentValidation<\/code> option:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.insertOne(\n  {\n    _id: 105,\n    \"name\": \"Carey\", \n    \"dob\": \"2003-7-2\"\n  }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the <code>validationAction<\/code> option were set to <code>error<\/code> (the default), the <code>insertOne<\/code> statement would return an error. Instead, the option is set to <code>warn<\/code>, so MongoDB adds the document to the collection and records the violation in the MongoDB log. (To view the log on Atlas, refer to the Atlas documentation.)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This principle works the same when updating documents. For example, the following <code>updateOne<\/code> statement attempts to update a field to an invalid value, without including the <code>bypassDocumentValidation<\/code> option:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateOne(\n  { _id : 105 },\n  { $set: { \"dob\" : \"2003-7-3\" } }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As with the <code>insertOne<\/code> statement, MongoDB does not return an error but instead updates the document and records the violation in the MongoDB log.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s modify our validation option settings, this time setting the <code>validationAction<\/code> option to <code>error<\/code> (the default) and the <code>validationLevel<\/code> option to <code>moderate<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.runCommand( { collMod: \"candidates\",\n  validator: {\n    $jsonSchema: {\n      bsonType: \"object\",\n      required: [ \"name\", \"dob\" ],\n      properties: {\n        \"name\": { bsonType: \"string\" },\n        \"dob\": { bsonType: \"date\" }\n      }\n    }\n  },\n  validationAction: \"error\",\n  validationLevel: \"moderate\"\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As you\u2019ll recall, the <code>candidates<\/code> collection includes two documents whose <code>dob<\/code> field is a <code>String<\/code> value and two documents whose <code>dob<\/code> field is a <code>Date<\/code> value. As a result, the documents with the <code>_id<\/code> values <code>101<\/code> and <code>103<\/code> are invalid.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s try to update the <code>103<\/code> document by changing the <code>dob<\/code> value from <code>1967-3-25<\/code> to <code>1968-3-25<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateOne(\n  { _id : 103 },\n  { $set: { \"dob\" : \"1968-3-25\" } }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the <code>validationLevel<\/code> option were set to <code>strict<\/code> (the default), the <code>updateOne<\/code> statement would return an error. Instead, MongoDB updates the document without generating an error or warning because the document was already invalid.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You can test this out further by running the following <code>updateOne<\/code> statement, which attempts to update a valid document with an invalid <code>dob<\/code> value:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.candidates.updateOne(\n  { _id : 104 },\n  { $set: { \"dob\" : \"1999-6-18\" } }\n);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This time, MongoDB will return an error stating that the document failed validation. Because the document is already valid, MongoDB applies the validation rules to the document when you try to update it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In some cases, you might want to set your validation options to their default values. For example, you might have changed them temporarily to test a particular scenario and now want to change them back. To return them to their default state, you can run the following <code>runCommand<\/code> statement:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">db.runCommand( { collMod: \"candidates\",\n  validator: {\n    $jsonSchema: {\n      bsonType: \"object\",\n      required: [ \"name\", \"dob\" ],\n      properties: {\n        \"name\": { bsonType: \"string\" },\n        \"dob\": { bsonType: \"date\" }\n      }\n    }\n  },\n  validationAction: \"error\",\n  validationLevel: \"strict\"\n});<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This statement will return the <code>candidates<\/code> collection to its default behavior, as it applies to the validation rules.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-summary-mongodb-validation-rules\">Summary: MongoDB validation rules<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In the previous article, I mentioned that schema validation can be a valuable tool for enforcing constraints on how a collection\u2019s documents are defined, but I also pointed out that you\u2019ll likely want to limit its use to more mature applications, when you don\u2019t require the same degree of flexibility you did when first setting up the collection. Enforcing schema validation on a schema prematurely can create more overhead. You should use schema validation judiciously until you fully understand how it will affect your applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With that in mind, you should now have a good foundation for working with schema validation in the MongoDB collection, at least enough to get started. There is certainly more that you can do with schema validation than what I\u2019ve covered here, so I recommend that you review other resources, particularly the MongoDB documentation. I suggest that you start with the topic <a href=\"https:\/\/www.mongodb.com\/docs\/manual\/core\/schema-validation\/\">Schema Validation<\/a>, which introduces you to validation rules in MongoDB.<\/p>\n\n\n\n<section id=\"my-first-block-block_5101391c7de2b61669bd5f3f3862882e\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Subscribe to the Simple Talk newsletter<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            All the latest articles, guides, podcasts, and more &#8211; delivered straight to your inbox.                                    <\/div>\n            <\/div>\n                                            <a href=\"https:\/\/www.red-gate.com\/simple-talk\/subscribe\/\" class=\"btn btn--secondary btn--lg\" aria-label=\"Subscribe now: Subscribe to the Simple Talk newsletter\">Subscribe now<\/a>\n                    <\/div>\n    <\/div>\n<\/section>\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. Does MongoDB apply new schema validation rules to documents already in a collection?<\/h3>\n            <div class=\"faq-answer\">\n                <p>No. Validation rules only apply going forward, to documents inserted or updated after the rules are defined. Documents already in the collection can remain invalid indefinitely unless you explicitly find and fix them.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. What&#039;s the difference between validationAction &quot;error&quot; and &quot;warn&quot; in MongoDB?<\/h3>\n            <div class=\"faq-answer\">\n                <p><code dir=\"ltr\">error<\/code> (the default) rejects any insert or update that violates the rules. <code dir=\"ltr\">warn<\/code> allows the operation to proceed anyway, but records the violation in the MongoDB log instead of blocking it.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What&#039;s the difference between validationLevel &quot;strict&quot; and &quot;moderate&quot; in MongoDB?<\/h3>\n            <div class=\"faq-answer\">\n                <p><code dir=\"ltr\">strict<\/code> (the default) applies validation rules to every insert and update. <code dir=\"ltr\">moderate<\/code> applies rules to all inserts, but for updates, only enforces them if the document being updated was already valid \u2014 an already-invalid document can still be updated without triggering the rules.<\/p>\n            <\/div>\n            <\/section>\n","protected":false},"excerpt":{"rendered":"<p>How to find, bypass, update, and delete documents that violate MongoDB schema validation rules \u2014 plus validationAction and validationLevel options.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":103515,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[143523,53,159161],"tags":[4168,5618,159226],"coauthors":[6779],"class_list":["post-103514","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-databases","category-featured","category-mongodb","tag-database","tag-mongodb","tag-mongodbseriesrobertsheldon"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103514","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=103514"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103514\/revisions"}],"predecessor-version":[{"id":113372,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/103514\/revisions\/113372"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/103515"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=103514"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=103514"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=103514"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=103514"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}