mongodb3.6.4_MongoDB 3.6中的JSON模式验证和富有表现力的查询语法

mongodb3.6.4

One of MongoDB’s key strengths has always been developer empowerment: by relying on a flexible schema architecture, MongoDB makes it easier and faster for applications to move through the development stages from proof-of-concept to production and iterate over update cycles as requirements evolve.

MongoDB的主要优势之一一直是增强开发人员能力:依靠灵活的架构体系结构,MongoDB使应用程序可以更轻松快捷地从概念验证到生产进入整个开发阶段,并根据需求的发展在更新周期中进行迭代。

However, as applications mature and scale, they tend to reach a stable stage where frequent schema changes are no longer critical or must be rolled out in a more controlled fashion, to prevent undesirable data from being inserted into the database. These controls are especially important when multiple applications write into the same database, or when analytics processes rely on predefined data structures to be accurate and useful.

但是,随着应用程序的成熟和扩展,它们趋于达到一个稳定的阶段,在此阶段,频繁的模式更改不再是关键性的,或必须以更受控制的方式推出,以防止将不良数据插入数据库中。 当多个应用程序写入同一数据库时,或者当分析过程依赖于预定义的数据结构来准确和有用时,这些控件尤为重要。

MongoDB 3.2 was the first release to introduce Document Validation, one of the features that developers and DBAs who are accustomed to relational databases kept demanding. As MongoDB’s CTO, Eliot Horowitz, highlighted in Document Validation and What Dynamic Schemas means:

MongoDB 3.2是第一个引入文档验证的版本 ,它是习惯于关系数据库的开发人员和DBA不断要求的功能之一。 作为MongoDB的CTO,埃利奥特·霍洛维茨(Eliot Horowitz)在文档验证和动态模式的含义中强调了以下内容:

Along with the rest of the 3.2 "schema when you need it" features, document validation gives MongoDB a new, powerful way to keep data clean. *These are definitely not the final set of tools we will provide, but is rather an important step in how MongoDB handles schema.***

文档验证与3.2的其余“需要时的架构”功能一起,为MongoDB提供了一种新的,功能强大的方式来保持数据干净。 *这些绝对不是我们将提供的最终工具集,而是MongoDB处理模式的重要一步。***

宣布JSON架构验证支持 ( Announcing JSON Schema Validation support )

Building upon MongoDB 3.2’s Document Validation functionality, MongoDB 3.6 introduces a more powerful way of enforcing schemas in the database, with its support of JSON Schema Validation, a specification which is part of IETF’s emerging JSON Schema standard.

在MongoDB 3.2的文档验证功能的基础上, MongoDB 3.6通过支持JSON Schema Validation(该规范是IETF新兴的JSON Schema标准的一部分)的支持,引入了一种更强大的数据库模式实施方法。

JSON Schema Validation extends Document Validation in many different ways, including the ability to enforce schemas inside arrays and prevent unapproved attributes from being added. These are the new features we will focus on in this blog post, as well as the ability to build business validation rules.

JSON模式验证以多种不同方式扩展了文档验证,包括在数组内强制执行模式并防止添加未经批准的属性的能力。 这些是我们将在此博客文章中重点介绍的新功能,以及建立业务验证规则的功能。

Starting with MongoDB 3.6, JSON Schema is the recommended way of enforcing Schema Validation. The next section highlights the features and benefits of using JSON Schema Validation.

从MongoDB 3.6开始,建议使用JSON模式来执行模式验证 。 下一节将重点介绍使用JSON模式验证的功能和好处。

从文档验证切换到JSON模式验证 ( Switching from Document Validation to JSON Schema Validation )

We will start by creating an orders collection (based on an example we published in the Document Validation tutorial blog post):

我们将首先创建一个订单集合(基于我们在Document Validation教程博客文章中发布的示例):

db.createCollection("orders", {
  validator: {
    item: { $type: "string" },
    price: { $type: "decimal" }
  }
});

With this document validation configuration, we not only make sure that both the item and price attributes are present in any order document, but also that item is a string and price a decimal (which is the recommended type for all currency and percentage values). Therefore, the following element cannot be inserted (because of the "rogue" price attribute):

使用此文档验证配置,我们不仅可以确保在任何订单文档中都同时存在商品和价格属性,而且还可以确保商品是一个字符串,价格是一个小数(这是所有货币和百分比值的推荐类型)。 因此,不能插入以下元素(由于“ rogue”价格属性):

db.orders.insert({
    "_id": 6666, 
    "item": "jkl", 
    "price": "rogue",
    "quantity": 1 });

However, the following document could be inserted (notice the misspelled "pryce" attribute):

但是,可以插入以下文档(请注意拼写错误的“ pryce”属性):

db.orders.insert({
    "_id": 6667, 
    "item": "jkl", 
    "price": NumberDecimal("15.5"),
    "pryce": "rogue" });

Prior to MongoDB 3.6, you could not prevent the addition of misspelled or unauthorized attributes. Let’s see how JSON Schema Validation can prevent this behavior. To do so, we will use a new operator, $jsonSchema:

在MongoDB 3.6之前,您无法阻止添加拼写错误或未经授权的属性。 让我们看看JSON模式验证如何防止这种行为。 为此,我们将使用一个新的运算符$ jsonSchema

db.runCommand({
  collMod: "orders",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["item", "price"],
      properties: {

       item: {
            bsonType: "string"
       },
       price: {
          bsonType: "decimal"
        }
      }
    }
  }
});

The JSON Schema above is the exact equivalent of the document validation rule we previously set above on the orders collection. Let’s check that our schema has indeed been updated to use the new $jsonSchema operator by using the db.getCollectionInfos() method in the Mongo shell:

上面的JSON模式与我们之前在订单集合上设置的文档验证规则完全相同。 让我们通过在Mongo shell中使用db.getCollectionInfos ()方法,检查我们的架构是否确实已更新为使用新的$ jsonSchema运算符:

db.getCollectionInfos({name:"orders"})

This command prints out a wealth of information about the orders collection. For the sake of readability, below is the section that includes the JSON Schema:

此命令打印出有关订单收集的大量信息。 为了便于阅读,下面是包含JSON模式的部分:

...
"options" : {
    "validator" : {
        "$jsonSchema" : {
            "bsonType" : "object",
            "required" : [
                "item",
                "price"
            ],
            "properties" : {
                "item" : {
                    "bsonType" : "string"
                },
                "price" : {
                    "bsonType" : "decimal"
                }
            }
        }
    },
    "validationLevel" : "strict",
    "validationAction" : "error"
}
...

Now, let’s enrich our JSON schema a bit to make better use of its powerful features:

现在,让我们丰富一下JSON模式,以更好地利用其强大功能:

db.runCommand({
  collMod: "orders",
  validator: {
    $jsonSchema: {
      bsonType: "object",
      additionalProperties: false,
      required: ["item", "price"],
      properties: {
       _id: {},
       item: {
            bsonType: "string",
            description: "'item' must be a string and is required"
        },
        price: {
          bsonType: "decimal",
          description: "'price' must be a decimal and is required"
        },
        quantity: {
          bsonType: ["int", "long"],
          minimum: 1,
          maximum: 100,
          exclusiveMaximum: true,
          description:
            "'quantity' must be short or long integer between 1 and 99"
        }
      }
    }
  }
});

Let’s go through the additions we made to our schema:

让我们看一下对模式所做的添加:

  • First, note the use of the additionalProperties:false attribute: it prevents us from adding any attribute other than those mentioned in the properties section. For example, it will no longer be possible to insert data containing a misspelled pryce attribute. As a result, the use of additionalProperties:false at the root level of the document also makes the declaration of the id property mandatory: whether our insert code explicitly sets it or not, it is a field MongoDB requires and would automatically create, if not present. Thus, we must include it explicitly in the properties section of our schema.

    首先,请注意使用了AdditionalProperties:false属性:它阻止我们添加属性部分中提到的那些属性以外的任何属性。 例如,将不再可能插入包含拼写错误的pryce属性的数据。 结果,在文档的根目录级别使用extraProperties:false也使id属性的声明成为强制性的:无论我们的插入代码是否显式设置它,它都是MongoDB要求的字段,如果没有,它将自动创建当下。 因此,我们必须在模式的属性部分中明确地包含它。
  • Second, we have chosen to declare the quantity attribute as either a short or long integer between 1 and 99 (using the minimum, maximum and exclusiveMaximum attributes). Of course, because our schema only allows integers lower than 100, we could simply have set the bsonType property to int. But adding long as a valid type makes application code more flexible, especially if there might be plans to lift the maximum restriction.

    其次,我们选择将数量属性声明为1到99之间的短整数或长整数(使用minimum,maximum和ExclusiveMaximum属性)。 当然,由于我们的架构仅允许小于100的整数,因此我们只需将bsonType属性设置为int即可。 但是,只要添加有效类型,就可以使应用程序代码更加灵活,尤其是在可能计划取消最大限制的情况下。
  • Finally, note that the description attribute (present in the item, price, and quantity attribute declarations) is entirely optional and has no effect on the schema aside from documenting the schema for the reader.

    最后,请注意,描述属性(出现在商品,价格和数量属性声明中)是完全可选的,除了为读者记录架构以外,对架构没有任何影响。

With the schema above, the following documents can be inserted into our orders collection:

使用上面的架构,可以将以下文档插入我们的订单集中:

db.orders.insert({ 
    "item": "jkl", 
    "price": NumberDecimal(15.50),
    "quantity": NumberInt(99)
  });

  db.orders.insert({ 
    "item": "jklm", 
    "price": NumberDecimal(15.50),
    "quantity": NumberLong(99)
  });

However, the following documents are no longer considered valid:

但是,以下文档不再被视为有效:

db.orders.insert({ 
    "item": "jkl", 
    "price": NumberDecimal(15.50),
    "quantity": NumberInt(100)
  });
  db.orders.insert({ 
    "item": "jkl", 
    "price": NumberDecimal(15.50),
    "quantity": "98"
  });
  db.orders.insert({ 
    "item": "jkl", 
    "pryce": NumberDecimal(15.50),
    "quantity": NumberInt(99)
  });

You probably noticed that our orders above are seemingly odd: they only contain one single item. More realistically, an order consists of multiple items and a possible JSON structure might be as follows:

您可能已经注意到我们上面的订单似乎很奇怪:它们只包含一个项目。 实际上,订单由多个项目组成,可能的JSON结构如下:

{
    _id: 10000,
    total: NumberDecimal(141),
    VAT: 0.20,
    totalWithVAT: NumberDecimal(169),
    lineitems: [
        {
            sku: "MDBTS001",
            name: "MongoDB Stitch T-shirt",
            quantity: NumberInt(10),
            unit_price:NumberDecimal(9)
        },
        {
            sku: "MDBTS002",
            quantity: NumberInt(5),
            unit_price: NumberDecimal(10)
        }
    ]
}

With MongoDB 3.6, we can now control the structure of the lineitems array, for instance with the following JSON Schema:

使用MongoDB 3.6,我们现在可以控制lineitems数组的结构,例如,使用以下JSON模式:

db.runCommand({
    collMod: "orders",
    validator: {
      $jsonSchema: {
        bsonType: "object",
        required: ["lineitems"],
        properties: {
        lineitems: {
              bsonType: ["array"],
              minItems: 1,
              maxItems:10,
              items: {
                  required: ["unit_price", "sku", "quantity"],
                  bsonType: "object",
                  additionalProperties: false,
                  properties: {
                      sku: {
                        bsonType: "string",
                        description: "'sku' must be a string and is required"
                      },
                      name: {
                        bsonType: "string",
                        description: "'name' must be a string"
                      },
                      unit_price: {
                        bsonType: "decimal",
                        description: "'unit_price' must be a decimal and is required"
                      },
                      quantity: {
                        bsonType: ["int", "long"],
                        minimum: 0,
                        maximum: 100,
                        exclusiveMaximum: true,
                        description:
                          "'quantity' must be a short or long integer in [0, 100)"
                      },
                  }
              }
          }
        }
      }
    }
  });

With the schema above, we enforce that any order inserted or updated in the orders collection contain a lineitems array of 1 to 10 documents that all have sku, unit_price and quantity attributes (with quantity required to be an integer)

使用上述模式,我们强制要求在订单集合中插入或更新的任何订单都包含一个由1至10个文档组成的lineitems数组,这些文档均具有sku, unit_price和数量属性( quantity必须为整数)

The schema would prevent inserting the following, badly formed document:

该架构将防止插入以下格式不正确的文档:

db.orders.insert({
        total: NumberDecimal(141),
        VAT: NumberDecimal(0.20),
        totalWithVAT: NumberDecimal(169),
        lineitems: [
            {
                sku: "MDBTS001",
                name: "MongoDB Stitch T-shirt",
                quantity: NumberInt(10),
                price: NumberDecimal(9) //this should be 'unit_price'
            },
            {
                name: "MDBTS002", //missing a 'sku' property
                quantity: NumberInt(5),
                unit_price: NumberDecimal(10)
            }
        ]
})

But it would allow inserting the following, schema-compliant document:

但这将允许插入以下符合架构的文档:

db.orders.insert({
        total: NumberDecimal(141),
        VAT: NumberDecimal(0.20),
        totalWithVAT: NumberDecimal(169),
        lineitems: [
            {
                sku: "MDBTS001",
                name: "MongoDB Stitch T-shirt",
                quantity: NumberInt(10),
                unit_price: NumberDecimal(9)
            },
            {
                sku: "MDBTS002",
                quantity: NumberInt(5),
                unit_price: NumberDecimal(10)
            }
        ]
})

However, if you pay close attention to the order above, you may notice that it contains a few errors:

但是,如果您密切注意上述顺序,您可能会注意到它包含一些错误:

  1. The totalWithVAT attribute value is incorrect (it should be equal to 141*1.20=169.2)

    totalWithVAT属性值不正确(应等于141 * 1.20 = 169.2)
  2. The total attribute value is incorrect (it should be equal to the sum of each line item sub-total, (i.e. 109+105=140)

    total属性值不正确(它应该等于每个行项子总的总和(即109 + 105 = 140)

Is there any way to enforce that total and totalWithVAT values be correct using database validation rules, without relying solely on application logic?

有什么方法可以使用数据库验证规则来强制totaltotalWithVAT值正确,而不必完全依赖于应用程序逻辑吗?

引入MongoDB表达查询语法 ( Introducing MongoDB expressive query syntax )

Adding more complex business validation rules is now possible thanks to the expressive query syntax, a new feature of MongoDB 3.6.

由于MongoDB 3.6的一项新功能即表达性查询语法,现在可以添加更复杂的业务验证规则。

One of the objectives of the expressive query syntax is to bring the power of MongoDB’s aggregation expressions to MongoDB’s query language. An interesting use case is the ability to compose dynamic validation rules that compute and compare multiple attribute values at runtime. Using the new $expr operator, it is possible to validate the value of the totalWithVAT attribute with the following validation expression:

表达查询语法的目标之一是将MongoDB 聚合表达式的功能引入MongoDB的查询语言 。 一个有趣的用例是能够组成动态验证规则,该规则可以在运行时计算和比较多个属性值。 使用新的$ expr运算符,可以使用以下验证表达式来验证totalWithVAT属性的值:

$expr: {
   $eq: [
     "$totalWithVAT",
     {$multiply: [
       "$total", 
       {$sum: [1, "$VAT"]}
     ]}
   ]
}

The above expression checks that the totalWithVAT attribute value is equal to total * (1+VAT). In its compact form, here is how we could use it as a validation rule, alongside our JSON Schema validation:

上面的表达式检查totalWithVAT属性值是否等于total * (1+VAT) 。 在紧凑的形式中,这是我们如何将其用作验证规则以及JSON Schema验证:

db.runCommand({
    collMod: "orders",
    validator: {
 $expr:{$eq:[
           "$totalWithVAT",
           {$multiply:["$total", {$sum:[1,"$VAT"]}]}
             ]},
      $jsonSchema: {
        bsonType: "object",
        required: ["lineitems"],
        properties: {
          lineitems: {
              bsonType: ["array"],
              minItems: 1,
              maxItems:10,
              items: {
                  required: ["unit_price", "sku", "quantity"],
                  bsonType: "object",
                  additionalProperties: false,
                  properties: {
                      sku: {
                        bsonType: "string",
                        description: "'sku' must be a string and is required"
                      },
                      name: {
                        bsonType: "string",
                        description: "'name' must be a string"
                      },
                      unit_price: {
                        bsonType: "decimal",
                        description: "'unit_price' must be a decimal and is required"
                      },
                      quantity: {
                        bsonType: ["int", "long"],
                        minimum: 0,
                        maximum: 100,
                        exclusiveMaximum: true,
                        description:
                          "'quantity' must be a short or long integer in [0, 100)"
                      },
                  }
              }
          }
        }
      }
    }
  });

With the validator above, the following insert operation is no longer possible:

使用上面的验证器,将不再可能进行以下插入操作:

db.orders.insert({
        total: NumberDecimal(141),
        VAT: NumberDecimal(0.20),
        totalWithVAT: NumberDecimal(169),
        lineitems: [
            {
                sku: "MDBTS001",
                name: "MongoDB Stitch T-shirt",
                quantity: NumberInt(10),
                Unit_price: NumberDecimal(9)
            },
            {
                sku: "MDBTS002",
                quantity: NumberInt(5),
                unit_price: NumberDecimal(10)
            }
        ]
})

Instead, the totalWithVAT value must be adjusted according to our new VAT validation rule:

相反,必须根据我们的新VAT验证规则调整totalWithVAT值:

db.orders.insert({
    total: NumberDecimal(141),
    VAT: NumberDecimal(0.20),
    totalWithVAT: NumberDecimal(169.2),
    lineitems: [
            {
                sku: "MDBTS001",
                name: "MongoDB Stitch T-shirt",
                quantity: NumberInt(10),
                unit_price: NumberDecimal(9)
            },
            {
                sku: "MDBTS002",
                quantity: NumberInt(5),
                unit_price: NumberDecimal(10)
            }
        ]
})

If we also want to make sure that the total value is the sum of each order line item value (i.e. quantityunit_price), the following expression should be used:

如果我们也要确保价值是每个订单行项目价值的总和(即,quantityunit_price),则应使用以下表达式:

$expr: { 
    $eq: [
       "$total", 
       {$sum: {
          $map: {
             "input": "$lineitems",
             "as": "item",
             "in": { 
                "$multiply": [
                   "$$item.quantity", 
                   "$$item.unit_price"
                ]
             } 
          }
       }}
    ]
  }

The above expression uses the $map operator to compute each line item’s sub-total, then sums all these sub-totals, and finally compares it to the total value. To make sure that both the Total and VAT validation rules are checked, we must combine them using the $and operator. Finally, our collection validator can be updated with the following command:

上面的表达式使用$ map运算符计算每个订单项的小计,然后所有这些小计求和 ,最后其与总值 进行比较 。 为了确保同时检查了Total和VAT验证规则,我们必须使用$ and运算符将它们组合在一起。 最后,可以使用以下命令来更新我们的集合验证器:

db.runCommand({
    collMod: "orders",
    validator: {
      $expr:{ $and:[
          {$eq:[ 
            "$totalWithVAT",
                   {$multiply:["$total", {$sum:[1,"$VAT"]}]}
          ]}, 
          {$eq: [
                   "$total", 
                {$sum: {$map: {
                    "input": "$lineitems",
                    "as": "item",
                    "in":{"$multiply":["$$item.quantity","$$item.unit_price"]}
                   }}}
             ]}
        ]},
      $jsonSchema: {
        bsonType: "object",       
        required: ["lineitems", "total", "VAT", "totalWithVAT"],
        properties: {
          total: { bsonType: "decimal" },
          VAT: { bsonType: "decimal" },
          totalWithVAT: { bsonType: "decimal" },
          lineitems: {
              bsonType: ["array"],
              minItems: 1,
              maxItems:10,
              items: {
                  required: ["unit_price", "sku", "quantity"],
                  bsonType: "object",
                  additionalProperties: false,
                  properties: {
                      sku: {bsonType: "string"},
                      name: {bsonType: "string"},
                      unit_price: {bsonType: "decimal"},
                      quantity: {
                        bsonType: ["int", "long"],
                        minimum: 0,
                        maximum: 100,
                        exclusiveMaximum: true

                      },
                  }                    
              }
          }
        }
      }
    }
  });

Accordingly, we must update the total and totalWithVAT properties to comply with our updated schema and business validation rules (without changing the lineitems array):

因此,我们必须更新totaltotalWithVAT属性以符合我们更新的架构和业务验证规则(不更改lineitems数组):

db.orders.insert({
      total: NumberDecimal(140),
      VAT: NumberDecimal(0.20),
      totalWithVAT: NumberDecimal(168),
      lineitems: [
          {
              sku: "MDBTS001",
              name: "MongoDB Stitch T-shirt",
              quantity: NumberInt(10),
              unit_price: NumberDecimal(9)
          },
          {
              sku: "MDBTS002",
              quantity: NumberInt(5),
              unit_price: NumberDecimal(10)
          }
      ]
  })

下一步 ( Next steps )

With the introduction of JSON Schema Validation in MongoDB 3.6, database administrators are now better equipped to address data governance requirements coming from compliance officers or regulators, while still benefiting from MongoDB’s flexible schema architecture.

通过在MongoDB 3.6中引入JSON模式验证,数据库管理员现在可以更好地满足合规官或监管机构提出的数据治理要求,同时仍可从MongoDB的灵活模式架构中受益。

Additionally, developers will find the new expressive query syntax useful to keep their application code base simpler by moving business logic from the application layer to the database layer.

此外,开发人员将发现新的表达查询语法对于通过将业务逻辑从应用程序层移动到数据库层来使他们的应用程序代码库更简单有用。

If you want to learn more about everything new in MongoDB 3.6, download our What’s New guide.

如果您想了解有关MongoDB 3.6新增功能的更多信息,请下载我们的新增功能指南。

If you want to get deeper on the technical side, visit the Schema Validation and Expressive Query Syntax pages in our official documentation.

如果您想深入了解技术方面,请访问我们官方文档中的Schema ValidationExpressive Query Syntax页面。

If you want to get more practical, hands-on experience, take a look at this JSON Schema Validation hands-on lab. You can try it right away on the MongoDB Atlas database service, which supports MongoDB 3.6 since its general availability date.

如果您想获得更多实用的动手经验,请查看此JSON Schema Validation动手实验 。 您可以立即在MongoDB Atlas数据库服务上试用它,该服务自MongoDB 3.6正式发布之日起就支持它。

Last but not least, sign up for our free MongoDB 3.6 training from MongoDB University.

最后但并非最不重要的一点是,从MongoDB大学注册我们免费的MongoDB 3.6培训

This article is sponsored by SyndicateAds.net

本文由SyndicateAds.net赞助

翻译自: https://scotch.io/tutorials/json-schema-validation-and-expressive-query-syntax-in-mongodb-36

mongodb3.6.4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值