MongoDB ObjectId Validator
Validate that a string is a valid MongoDB ObjectId: 24 hex chars. Shows embedded timestamp (first 4 bytes).
MongoID in Mongoose: validating the _id field beyond plain ObjectId
MongoID is the informal name often used for the _id identifier in Mongoose, the most popular ODM (Object Data Modeling) library for MongoDB on Node.js. Created by Valeri Karpov at LearnBoost in 2010, Mongoose adds schemas, validation, hooks, virtuals and population on top of the native MongoDB driver โ and the way it handles document identifiers is one of its most distinctive features.
By default, every Mongoose document gets an auto-generated _id field of type ObjectId: a 12-byte BSON value rendered as a 24-character hexadecimal string like 507f1f77bcf86cd799439011. Mongoose injects this field implicitly unless you opt out with _id: false in the schema options.
Defining and customizing _id in a Mongoose schema
Although ObjectId is the default, Mongoose lets you swap _id for any other type โ UUIDs, integers, slug strings or composite keys are all valid choices when business logic requires them.
const userSchema = new Schema({
_id: { type: Schema.Types.ObjectId, default: () => new mongoose.Types.ObjectId() },
email: String
});
// Custom string _id (e.g. slug):
const articleSchema = new Schema({ _id: String, title: String });
Use ref: 'User' on a referenced field to declare a relationship, then .populate('user') at query time to resolve the foreign _id into the full referenced document โ the canonical Mongoose pattern for cross-collection joins.
Validating a MongoID: ObjectId.isValid() and its pitfalls
The official check is mongoose.Types.ObjectId.isValid(str), which returns true when the input could be coerced into an ObjectId. Watch out for the classic gotcha: isValid() also returns true for any 12-character string (because 12 bytes is also a legal ObjectId binary length). Production code that only accepts the 24-hex format should add an explicit regex check:
function isValidMongoId(s) {
return typeof s === 'string'
&& /^[a-fA-F0-9]{24}$/.test(s)
&& mongoose.Types.ObjectId.isValid(s);
}
Client-side generation, security and UUID v7 parallels
ObjectIds can be generated either on the client (the MongoDB driver does this by default before inserts) or on the server. Client-side generation is fine for non-security-critical IDs because the timestamp prefix and counter are not secrets โ but never expose ObjectIds in public URLs for resources where guessability matters, since the timestamp segment leaks creation order and approximate time.
The pattern (timestamp prefix + entropy + counter) is conceptually close to UUID v7, standardized in RFC 9562 (2024): both produce roughly time-sortable identifiers with random tail bits. If you are starting a new project today and want chronological ordering across heterogeneous data stores, UUID v7 is the cross-ecosystem standard; ObjectId remains the path of least resistance inside the MongoDB world.
Mongoose vs the raw MongoDB Node.js driver
- Mongoose: higher-level ODM โ schemas, validators, middleware, virtuals, populate. Auto-injects
_id, casts strings to ObjectId for you. - Driver: thin wrapper around the wire protocol. You manage casting and validation yourself with
new ObjectId(str). - MongoDB Atlas: managed cloud service from MongoDB Inc. โ both libraries connect to it the same way.
- Brazilian Node ecosystem: Mongoose is the dominant choice in the BR stack โ most tutorials, courses and production codebases use it.
FAQ
Mongoose vs the MongoDB driver โ which one validates the _id?
Both expose ObjectId.isValid(), but Mongoose also performs automatic casting via the schema โ if you declare type: ObjectId, strings are coerced and rejected through Mongoose's CastError when malformed. The driver leaves all of that to your application code.
Can the client generate an ObjectId?
Yes โ and that's the default in the Node.js driver. new mongoose.Types.ObjectId() on the client produces a valid ID that the server accepts. Avoid it only when ID confidentiality is a security requirement.
Are there quirks in ObjectId.isValid()?
Yes โ it returns true for any 12-character string because those map to 12 raw bytes. If your API contract is "24 hex characters", combine the check with a regex like /^[a-fA-F0-9]{24}$/.
Why 24 hexadecimal characters?
An ObjectId is 12 bytes (96 bits). Each byte is represented as 2 hex digits, giving 24 characters total: 4 bytes of timestamp, 5 bytes of random per-process value and 3 bytes of incrementing counter.
Can I use UUID instead of ObjectId in Mongoose?
Yes โ declare _id: { type: String, default: () => crypto.randomUUID() } (or use Buffer/UUID v7 libs) on your schema. You lose the built-in sortability of ObjectId but gain a cross-platform identifier.
Related Tools
CPF Validator
Validate Brazilian CPF numbers instantly using the official algorithm. Useful for testing document validation in applications. No data sent to servers.
Batch CPF Validator
Validate a list of CPFs (one per line) and see which are valid and which are not. No data sent to servers.
Batch CNPJ Validator
Validate a list of CNPJs (one per line) with a summary of valid, invalid and total. No data sent to servers.