Practical Lab: Build a BSON Type Audit Dataset
This lab combines the chapter's most important type concepts in a single dataset. Use a dedicated development database and collection.
Step 1: Insert deliberately varied documents
use mongodb_course_lab
db.bsonLab.insertMany([
{
name: "Arun",
age: NumberInt(28),
salary: NumberDecimal("55000.50"),
active: true,
skills: ["Node.js", "MongoDB"],
address: { city: "Chennai" },
createdAt: ISODate("2026-10-01T10:00:00Z")
},
{
name: "Meera",
age: NumberLong("35"),
salary: NumberDecimal("72000.00"),
active: false,
skills: ["React", "TypeScript"],
address: { city: "Bengaluru" },
createdAt: ISODate("2026-10-05T12:00:00Z")
},
{
name: "Ravi",
age: "30",
salary: "60000.00",
active: "true",
skills: ["JavaScript"],
createdAt: "2026-10-10T09:00:00Z"
},
{
name: "Kavitha",
age: NumberInt(42),
salary: null,
active: true,
skills: [],
createdAt: null
},
{
name: "Divya",
age: NumberInt(26),
salary: NumberDecimal("48000.00"),
active: true,
skills: ["MongoDB", "Node.js"],
createdAt: ISODate("2026-10-15T09:30:00Z")
}
]);
The collection intentionally includes numeric strings, a Boolean string, a date string, explicit null values, and missing fields.
Step 2: Inspect the documents
db.bsonLab.find();
Identify fields whose types differ across documents.
Step 3: Inspect field types using aggregation
db.bsonLab.aggregate([
{
$project: {
name: 1,
ageType: { $type: "$age" },
salaryType: { $type: "$salary" },
activeType: { $type: "$active" },
createdAtType: { $type: "$createdAt" }
}
}
]);
Notice the difference between missing, null, string, int, long, decimal, bool, and date where applicable.
Step 4: Find incorrectly typed ages
db.bsonLab.find({
age: { $type: "string" }
});
This identifies documents whose age value is a string.
Step 5: Find numeric salary values
db.bsonLab.aggregate([
{
$project: {
name: 1,
salary: 1,
salaryIsNumber: { $isNumber: "$salary" }
}
}
]);
Use this output to identify documents with numeric salary values and documents whose salary is null or a string.
Step 6: Convert values in a read-only pipeline
db.bsonLab.aggregate([
{
$project: {
name: 1,
normalizedSalary: {
$convert: {
input: "$salary",
to: "decimal",
onError: null,
onNull: null
}
}
}
}
]);
This illustrates how conversion could help normalize values. It does not modify the stored documents.
Step 7: Query a nested field
db.bsonLab.find({ "address.city": "Chennai" });
This returns documents whose nested city field matches Chennai.
Step 8: Query a date range
db.bsonLab.find({
createdAt: {
$gte: ISODate("2026-10-01T00:00:00Z"),
$lt: ISODate("2026-10-16T00:00:00Z")
}
});
Only BSON Date values in the requested interval match this date range. A string that looks like a date is not treated as a BSON Date.
Step 9: Explore the array field
db.bsonLab.find({ skills: "MongoDB" });
This matches documents whose skills array contains MongoDB.
Step 10: Explain the data-quality risks
Write down the problems caused by inconsistent types:
- Numeric range queries may not include numeric strings.
- Boolean filters do not treat
"true"as Boolean true. - Date range queries do not automatically interpret date strings as BSON Dates.
- Null and missing values may have different business meanings.
- Aggregation and arithmetic can fail or produce unexpected results when types are inconsistent.
Lab challenge
Design a migration plan that converts age to a numeric type, salary to Decimal128, and createdAt to BSON Date. Your plan should identify invalid values, avoid overwriting data without inspection, test conversion results, and apply schema validation after the data is normalized.
db.bsonLab.aggregate([
{
$project: {
name: 1,
ageType: { $type: "$age" },
salaryType: { $type: "$salary" },
activeType: { $type: "$active" },
createdAtType: { $type: "$createdAt" },
skillsType: { $type: "$skills" },
salaryIsNumber: { $isNumber: "$salary" }
}
}
]);- A single collection can contain inconsistent field types unless appropriate controls prevent them.
- The aggregation
$typeexpression is useful for data audits. - Numeric strings, Boolean strings, and date strings are not equivalent to their BSON counterparts.
- A read-only conversion pipeline allows you to inspect normalization results before modifying data.
- Data migrations should be tested, observable, and followed by validation.
In the lab dataset, why does the date range query not match Ravi's `createdAt` value?