介绍
在本实验中,你将学习如何验证 MongoDB 的数据类型、处理无效数据以及防止不良输入,以维护 MongoDB 数据库中的数据完整性。你将首先探索 MongoDB 支持的不同数据类型,并创建一个具有特定数据类型要求的示例集合。然后,你将练习插入类型不正确的文档,并学习如何正确插入符合验证标准的数据。通过本实验,你将深入了解 MongoDB 的数据验证和错误处理技术。
在本实验中,你将学习如何验证 MongoDB 的数据类型、处理无效数据以及防止不良输入,以维护 MongoDB 数据库中的数据完整性。你将首先探索 MongoDB 支持的不同数据类型,并创建一个具有特定数据类型要求的示例集合。然后,你将练习插入类型不正确的文档,并学习如何正确插入符合验证标准的数据。通过本实验,你将深入了解 MongoDB 的数据验证和错误处理技术。
在这一步骤中,你将学习如何检查和验证 MongoDB 中的数据类型,这对于维护数据完整性和防止数据库中的错误至关重要。
MongoDB 支持多种数据类型,包括:
让我们首先打开 MongoDB shell 并探索数据类型验证:
mongosh
我们将创建一个具有特定数据类型要求的 users
集合:
use dataValidationLab
db.createCollection("users", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "age", "email"],
properties: {
name: {
bsonType: "string",
description: "必须是一个字符串且为必填项"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 120,
description: "必须是一个介于 18 和 120 之间的整数"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "必须是一个有效的电子邮件地址"
}
}
}
}
})
让我们分解一下验证规则:
bsonType: "string"
确保字段是一个字符串bsonType: "int"
确保字段是一个整数minimum
和 maximum
设置范围约束pattern
验证电子邮件格式现在,让我们尝试插入文档以测试我们的验证规则:
// 由于年龄类型不正确,此操作将失败
db.users.insertOne({
name: "John Doe",
age: "25", // 字符串而不是整数
email: "[email protected]"
});
// 由于电子邮件无效,此操作也将失败
db.users.insertOne({
name: "Jane Smith",
age: 30,
email: "invalid-email"
});
以下是插入有效文档的方式:
db.users.insertOne({
name: "Alice Johnson",
age: NumberInt(28),
email: "[email protected]"
});
注意使用 NumberInt()
显式创建一个整数。
在这一步骤中,我们将基于之前的数据验证工作,重点确保 MongoDB 文档中始终包含必填字段。
必填字段是每个文档中必须包含的关键信息。在之前的步骤中,我们创建了一个包含必填字段的验证模式。现在,我们将探讨如何强制执行和验证这些要求。
让我们继续在 MongoDB shell 中操作:
mongosh
切换到我们现有的数据库:
use dataValidationLab
我们将修改现有的 users
集合,以强制执行严格的必填字段验证:
db.runCommand({
collMod: "users",
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "age", "email", "registrationDate"],
properties: {
name: {
bsonType: "string",
description: "姓名是必填项且必须为字符串"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 120,
description: "年龄是必填项且必须为介于 18 和 120 之间的整数"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "电子邮件是必填项且必须为有效的电子邮件地址"
},
registrationDate: {
bsonType: "date",
description: "注册日期是必填项且必须为日期"
}
}
}
},
validationLevel: "strict"
});
让我们尝试插入缺少必填字段的文档:
// 由于缺少 registrationDate,此操作将失败
db.users.insertOne({
name: "Bob Wilson",
age: NumberInt(35),
email: "[email protected]"
});
// 由于缺少必填字段,此操作也将失败
db.users.insertOne({
name: "Charlie Brown"
});
以下是插入符合所有要求的文档的方式:
db.users.insertOne({
name: "Emma Thompson",
age: NumberInt(42),
email: "[email protected]",
registrationDate: new Date()
});
为了理解插入失败的原因,MongoDB 提供了验证错误信息:
try {
db.users.insertOne({
name: "Incomplete User"
});
} catch (error) {
print("Validation Error:", error.message);
}
这将帮助你准确了解缺少了哪些必填字段。
在这一步骤中,我们将学习如何处理和管理 MongoDB 中的无效数据,重点关注错误捕获、日志记录以及实现数据验证策略。
让我们继续在 MongoDB shell 中操作:
mongosh
切换到我们现有的数据库:
use dataValidationLab
我们将创建一个具有高级验证和错误处理的新集合:
db.createCollection("products", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "price", "category"],
properties: {
name: {
bsonType: "string",
minLength: 2,
maxLength: 100
},
price: {
bsonType: ["double", "int"],
minimum: 0,
description: "价格必须为正数"
},
category: {
enum: ["Electronics", "Clothing", "Books", "Food"],
description: "类别必须是预定义值之一"
}
}
}
},
validationAction: "error"
});
我们将创建一个函数来处理无效数据的插入:
function safeInsertProduct(product) {
try {
db.products.insertOne(product);
print("产品插入成功:", product.name);
} catch (error) {
print("插入产品时出错:", error.message);
// 将无效数据记录到单独的集合中
db.invalidProducts.insertOne({
product: product,
errorMessage: error.message,
timestamp: new Date()
});
}
}
让我们通过多种场景测试我们的错误处理机制:
// 有效的产品插入
safeInsertProduct({
name: "Smartphone",
price: 599.99,
category: "Electronics"
});
// 无效的产品 - 价格类型错误
safeInsertProduct({
name: "Laptop",
price: "1000", // 字符串而不是数字
category: "Electronics"
});
// 无效的产品 - 无效类别
safeInsertProduct({
name: "T-Shirt",
price: 29.99,
category: "Accessories" // 不在预定义类别中
});
// 无效的产品 - 名称过短
safeInsertProduct({
name: "A",
price: 10,
category: "Books"
});
让我们检查无效产品的日志:
print("无效产品日志:");
db.invalidProducts.find();
在这一步骤中,我们将学习如何识别和纠正 MongoDB 中的数据问题,重点关注数据清理和转换策略。
让我们继续在 MongoDB shell 中操作:
mongosh
切换到我们现有的数据库:
use dataValidationLab
我们将创建一个可能包含问题数据的集合:
db.createCollection("customers", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["name", "email", "age"],
properties: {
name: {
bsonType: "string",
minLength: 2
},
email: {
bsonType: "string",
pattern: "^.+@.+$"
},
age: {
bsonType: "int",
minimum: 18,
maximum: 120
}
}
}
}
});
// 插入一些可能存在问题数据的示例数据
db.customers.insertMany([
{ name: "John Doe", email: "john@example", age: "35" },
{ name: "A", email: "invalid-email", age: 15 },
{ name: "Jane Smith", email: "[email protected]", age: 25 }
]);
让我们创建一个函数来清理和验证客户数据:
function cleanCustomerData() {
// 查找并修复无效文档
const invalidCustomers = db.customers.find({
$or: [
{ age: { $type: "string" } },
{ email: { $not: /^.+@.+$/ } },
{
name: { $exists: true, $expr: { $lt: [{ $strLenBytes: "$name" }, 2] } }
}
]
});
invalidCustomers.forEach((customer) => {
// 修复年龄:转换为整数
const fixedAge =
typeof customer.age === "string"
? parseInt(customer.age)
: customer.age < 18
? 18
: customer.age;
// 修复电子邮件:如果缺少域名则添加
const fixedEmail = customer.email.includes("@")
? customer.email
: `${customer.email}@example.com`;
// 修复名称:填充过短的名称
const fixedName =
customer.name.length < 2 ? customer.name.padEnd(2, "X") : customer.name;
// 使用修正后的数据更新文档
db.customers.updateOne(
{ _id: customer._id },
{
$set: {
age: NumberInt(fixedAge),
email: fixedEmail,
name: fixedName
}
}
);
print(`修复客户: ${customer.name}`);
});
// 验证清理后的数据
print("清理数据验证:");
db.customers.find().forEach(printjson);
}
// 运行清理函数
cleanCustomerData();
让我们验证清理后的数据是否符合我们的验证标准:
function validateCustomers() {
const invalidCustomersCount = db.customers
.find({
$or: [
{ age: { $not: { $type: "int" } } },
{ age: { $lt: 18, $gt: 120 } },
{ email: { $not: /^.+@.+$/ } },
{
name: {
$exists: true,
$expr: { $lt: [{ $strLenBytes: "$name" }, 2] }
}
}
]
})
.count();
print(`剩余无效客户数量: ${invalidCustomersCount}`);
return invalidCustomersCount === 0;
}
validateCustomers();
在这最后一步中,我们将探索通过全面的验证策略来防止不良输入并增强 MongoDB 中的数据完整性的高级技术。
让我们继续在 MongoDB shell 中操作:
mongosh
切换到我们现有的数据库:
use dataValidationLab
我们将为 registrations
集合创建一个全面的验证模式:
db.createCollection("registrations", {
validator: {
$jsonSchema: {
bsonType: "object",
required: ["username", "email", "password", "registrationDate"],
properties: {
username: {
bsonType: "string",
minLength: 3,
maxLength: 20,
pattern: "^[a-zA-Z0-9_]+$",
description: "用户名必须为字母数字,长度为 3-20 个字符"
},
email: {
bsonType: "string",
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
description: "必须为有效的电子邮件地址"
},
password: {
bsonType: "string",
minLength: 8,
description: "密码必须至少为 8 个字符",
pattern:
"^(?=.*[A-Za-z])(?=.*\\d)(?=.*[@$!%*#?&])[A-Za-z\\d@$!%*#?&]{8,}$"
},
registrationDate: {
bsonType: "date",
description: "注册日期必须为有效日期"
}
}
}
},
validationAction: "error",
validationLevel: "strict"
});
创建一个函数以在插入前验证输入:
function safeRegister(userData) {
// 清理并验证输入
const sanitizedData = {
username: userData.username.trim().toLowerCase(),
email: userData.email.trim().toLowerCase(),
password: userData.password,
registrationDate: new Date()
};
// 额外的自定义验证
if (sanitizedData.username.length < 3) {
throw new Error("用户名过短");
}
if (db.registrations.findOne({ username: sanitizedData.username })) {
throw new Error("用户名已存在");
}
if (db.registrations.findOne({ email: sanitizedData.email })) {
throw new Error("电子邮件已注册");
}
try {
// 尝试插入并触发 MongoDB 验证
db.registrations.insertOne(sanitizedData);
print("注册成功:", sanitizedData.username);
} catch (error) {
print("注册失败:", error.message);
// 记录失败的注册尝试
db.registrationAttempts.insertOne({
attemptData: userData,
errorMessage: error.message,
timestamp: new Date()
});
}
}
// 测试输入预防
function testRegistrations() {
const testCases = [
// 有效注册
{
username: "john_doe",
email: "[email protected]",
password: "Strong!Pass123"
},
// 无效案例
{ username: "ab", email: "invalid-email", password: "short" },
{ username: "john_doe!", email: "[email protected]", password: "WeakPass" },
{
username: "special_chars!",
email: "invalid@email",
password: "NoSpecialChar123"
}
];
testCases.forEach((testCase) => {
print("\n测试注册:");
printjson(testCase);
safeRegister(testCase);
});
}
// 运行注册测试
testRegistrations();
检查记录的注册尝试:
print("失败的注册尝试:");
db.registrationAttempts.find();
在本实验中,你学习了如何检查和验证 MongoDB 中的数据类型,以维护数据完整性并防止数据库中的错误。你探索了 MongoDB 支持的各种数据类型,包括字符串(string)、整数(integer)、双精度浮点数(double)、布尔值(boolean)、数组(array)、对象(object)、日期(date)、ObjectId 和 null。你创建了一个具有特定数据类型要求的示例用户集合(users collection),例如确保名称是字符串、年龄是介于 18 到 120 之间的整数,以及电子邮件是有效的电子邮件地址。你还学习了如何处理无效数据,通过尝试插入类型不正确的文档并理解错误信息。
最后,你练习了插入具有正确数据类型的文档,以成功将它们添加到用户集合中。