14

Is there a way to validate a MongoDB ObjectId without actually hitting the MongoDB database at all? For example, the string value "5c0a7922c9d89830f4911426" should result in "true".

mickl
  • 48,568
  • 9
  • 60
  • 89
Raj Chaudhary
  • 1,444
  • 3
  • 16
  • 31
  • 1
    Can you explain if you want to know if the ObjectId actually _exists_, or is it okay for you if it just a potential valid ObjectId string? Because in the latter case the answers here might help you: https://stackoverflow.com/questions/11985228/mongodb-node-check-if-objectid-is-valid – Virginia Dec 08 '18 at 20:19

7 Answers7

32

You can use .isValid() method on ObjectId, try in mongoose:

var mongoose = require('mongoose');
var isValid = mongoose.Types.ObjectId.isValid('5c0a7922c9d89830f4911426'); //true
mickl
  • 48,568
  • 9
  • 60
  • 89
  • what happened if I pass a stirng with the length of 12? `var isValid = mongoose.Types.ObjectId.isValid('lkjyuhgfdres')` – Sudarshana Dayananda Feb 21 '20 at 05:16
  • @SudarshanaDayananda of course it cannot be valid since it contains non-hexadecimal characters – mickl Feb 21 '20 at 14:17
  • but in the question there is nothing about hexadecimal/non-hexadecimal. It is about validating any string whether it is valid MongoDB id or not – Sudarshana Dayananda Feb 23 '20 at 05:02
  • @SudarshanaDayananda A valid MongoDB ObjectID only contains hexadecimal characters. So a string like "lkjyuhgfdres" is obviously not a valid ObjectID. Also be aware of that this only validates that the id is VALID, not if it EXISTS inside a database. – mhombach May 08 '21 at 16:04
  • 1
    any 12 char string passes this – Tushar Shahi Jan 25 '22 at 14:22
  • @TusharShahi yes you are correct; I suggest use this small npm package https://www.npmjs.com/package/joi-objectid – Abd Sep 03 '22 at 07:38
7

Please note that in almost all scenarios you just have to handle the catch and not bother with the validity of the ObjectID since mongoose would complain throw if invalid ObjectId is provided.

Model.findOne({ _id: 'abcd' }).exec().catch(error => console.error('error', error));

Other than that you could either use the mongoose.Types.ObjectId.isValid or a regular expression: /^[a-fA-F0-9]{24}$/

Akrion
  • 18,117
  • 1
  • 34
  • 54
2

@mickl's Answer will be failed for the strings with the length of 12.

You should convert any given string to MongoDB ObjectId using ObjectId constructor in mongodb and then cast it to a string and the check again with the original one. It should be the same.

  import { ObjectId } from 'mongodb'

  function isValidId(id) {

     return new ObjectId(id).toString() === id;
  }

  isValidId('5c0a7922c9d89830f4911426')// true
  isValidId('lkjyuhgfdres')// false
Sudarshana Dayananda
  • 5,165
  • 2
  • 23
  • 45
  • 2
    This doesn't work for me, it crashes the mongodb client with the same error of "Argument passed in must be a single String of 12 bytes or a string of 24 hex characters". – Sam Sverko Nov 02 '20 at 17:19
  • 1
    Wrap it in a trycatch? try returns true, catch returns false... – TJBlackman Aug 04 '22 at 14:58
0

The API provided (Mongoose.prototype.isValidObjectId() and for newer versions and ) returns true for random strings like Manajemenfs2.

With mongoose this is how I ended up doing it:

import mongoose from 'mongoose';


const isValidMongoId = (id: string) => {  
  try {
    const objectID = new mongoose.Types.ObjectId(id);
    const objectIDString = objectID.toString();
    return objectIDString === id;
  } catch (e){
    return false;
  } 
};

The definition of the method clearly shows:


Mongoose.prototype.isValidObjectId = function(v) {
  if (v == null) {
    return true;
  }

  //Other code

  if (v.toString instanceof Function) {
    v = v.toString();
  }

  if (typeof v === 'string' && v.length === 12) {
    return true;
  }

  //Other code

  return false;
};

that for general primitive strings and even string objects, any string of length 12 passes.

Tushar Shahi
  • 16,452
  • 1
  • 18
  • 39
0
let mongoose = require('mongoose'); 
let ObjectId = mongoose.Types.ObjectId; 
let recId1 = "621f1d71aec9313aa2b9074c"; 
let isValid1 = ObjectId.isValid(recId1); //true 
console.log("isValid1 = ", isValid1); //true 
let recId2 = "621f1d71aec9313aa2b9074cd"; 
let isValid2 = ObjectId.isValid(recId2); //false
console.log("isValid2 = ", isValid2); //false
  • 1
    As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 12 '22 at 07:19
0

If you use Joi for validating, you can include validation directly in your Joi schemas, using joi-objectid:

Install joi-objectid: $ npm i joi-objectid

Define the function to use globally (with Joi already imported):

Joi.objectId = require('joi-objectid')(Joi)

Use it in your Joi schema:

function validateUser(user) {
    const schema = {
        userId: Joi.objectId().required(),
        name: Joi.string().required()
    };
    return Joi.validate(user, schema);
}
Guscie
  • 2,278
  • 2
  • 26
  • 33
0

You can use an inbuilt function in mongoose

import { isValidObjectId } from "mongoose";

const isIDValid = isValidObjectId(id);

if (!isIDValid) throw { message: `Invalid ID provided` };
Chukwuemeka Maduekwe
  • 6,687
  • 5
  • 44
  • 67