New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Best way to validate an ObjectId #1959
Comments
I'm having the same problem. I tried mongoose.Schema.ObjectId.isValid() as well as mongoose.Types.ObjectId.isValid() but neither of those properties have an isValid method. How did you end up solving this problem? I also see mongodb has one and there is also regex as another option. I would prefer to not use regex nor have to require('mongodb') |
This works for me: var mongoose = require('./node_modules/mongoose'); |
Incidentally the method in mongodb is the bson lib method, which just checks for not null, 12 or 24 char hex string - it's a regex like this: var checkForHexRegExp = new RegExp("^[0-9a-fA-F]{24}$"); so it can't be too hacky if it's used in there |
sValid() always returns True if string contains 12 letters console.log(mongoose.Types.ObjectId.isValid("zzzzzzzzzzzz")); // true |
Because "zzzzzzzzzzzz" is technically a valid ObjectId - an object id's only defining feature is that its 12 bytes long. See mongodb/js-bson#112. A JS string of length 12 has 12 bytes, modulo unicode weirdnesses. If you want to check for a length 24 hex string, just check the string matches |
"zzzzzzzzzzzz" is not valid ObjectId. For example Mongo shell listiong (mongodb version - 3.0.2): > ObjectId('zzzzzzzzzzzz')
2015-04-29T18:05:20.705+0300 E QUERY Error: invalid object id: length
at (shell):1:1
> ObjectId('zzzzzzzzzzzzzzzzzzzzzzzz')
2015-04-29T18:06:09.773+0300 E QUERY Error: invalid object id: not hex
at (shell):1:1
> ObjectId('ffffffffffff')
2015-04-29T18:09:17.303+0300 E QUERY Error: invalid object id: length
at (shell):1:1
> ObjectId('ffffffffffffffffffffffff')
ObjectId("ffffffffffffffffffffffff") |
Because the mongodb shell's ObjectId constructor is written such that it only accepts hex strings. It's a restriction in the mongo shell for convenience, not with the BSON type ObjectId. Admittedly this is a somewhat counterintuitive case given that hex strings are how ObjectIds are usually represented, but if you don't like it then just use the regex |
Why do we get false when we try to do |
@niftylettuce comments welcome at #3365. Right now we just defer down to the bson package's ObjectId.isValid() function, which doesn't line up exactly with how people think of ObjectIds in mongoose. I'll open up a PR for returning true if you're given an ObjectId though, that seems perfectly reasonable. |
Coming back to a bit of an old issue here... @atcwells solution Ideally, it would simply return something in the Is there a use-case where this wouldn't be useful functionality in core? If not, perhaps we can make a plugin. I've had a quick search and there doesn't seem to be anything the does the job – https://github.com/CampbellSoftwareSolutions/mongoose-id-validator is for validating that the ID actually exists, which isn't what we want to do here – we simply want to make sure that we don't generate an uncaught error. |
Right now, in my Express controller, every time I go a request that has an ObjectId in it, e.g. GET to https://myproject/organisations/{id}, I have to do something like:
... before then going on to do Seems pretty boilerplate. I'm happy to write a plugin or something if someone can point me in the right direction of where to start. Doesn't seem like a plugin as it's not really a schema thing... |
@shankiesan you don't need to do that, mongoose will reject the query promise if the id is invalid. var assert = require('assert');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/test');
mongoose.set('debug', true);
var MyModel = mongoose.model('test', new Schema({ name: String }));
MyModel.findOne({ _id: 'invalid' }).exec().catch(error => console.error('error', error)); Output:
|
Also, re: plugins http://thecodebarbarian.com/2015/03/06/guide-to-mongoose-plugins |
Ah what a muppet I've been! Of course, handle the promise being rejected... arg, my brain. Thanks @vkarpov15 |
Callbacks work too if promises are too much of a headache |
DO NOT USE |
@atcwells if you could update your highly upvoted comment to include that bit I think other people might appreciate it since I was initially doing it based on what you said: |
The funny part is: |
What I'm rolling with (for now) is checking the error type in the promise catch. If it's 'ObjectId' I am returned a 404. I am returning a 404 because to the consumer of the API/Web service the resource was not found or doesn't exist. See example:
UPDATE: See example:
|
Is it possible validate in the schema? Is not a best practice repeat that if, but i want to log cast error event. |
Why can't mongoose implement the regex /^[a-fA-F0-9]{24}$/ for isValid when it is only dealing with MongoDB. This is so confusing. We just spend an hour debugging the issue and it came out to be such a silly thing that you will never notice |
I would recommend to use this npm package https://www.npmjs.com/package/valid-objectid |
I've created a workaround for this:
|
@mstmustisnt I think that needs to be try/catched, if value is "123" this will throw an error. |
In case it helps anyone, I've been doing an adaptation of the
...I've found that this works well in my controller: const { id } = req.params;
const query = {
$or: [{ slug: id }],
};
if (mongoose.Types.ObjectId.isValid(id)) query.$or.push({ _id: id });
User.findOne(query)
.exec((err, user) => { ... } In this case, a 12-byte string is still a valid Object ID, searching for it simply returns a zero-length array, rather than throwing an error. And because I'm using an Might not be the most elegant solution, but it works for me. |
@victorbadila yes, exactly. I just gave a hint. Edited my comment, actually just places the code I actually use. |
validator.js has a built-in |
Whenever I use mongoose, I always extend it with a few static helper methods: const mongoose = require('mongoose');
const {Types: {ObjectId}} = mongoose;
//Helper to check if an ID is an object ID
mongoose.isObjectId = function(id) {
return (id instanceof ObjectId);
};
//Helper to validate a string as object ID
mongoose.isValidObjectId = function(str) {
if (typeof str !== 'string') {
return false;
}
return str.match(/^[a-f\d]{24}$/i);
}; You can run this as a part of your database initialisation scripts, so the methods are always available in your app. |
fix(ObjectID): isValid(new ObjectID()) returns true
If ObjectId.isValid(id) is true, we can judge (new ObjectId(id).toString()) 's value and id. const mongoose = require('mongoose');
const {Types: {ObjectId}} = mongoose;
const validateObjectId = (id) => ObjectId.isValid(id) && (new ObjectId(id)).toString() === id; |
I'm inserting some objectIds as references and I want to make sure that they are valid objectids (right now I'm getting a crash when they aren't valid ids).
I'm checking to see if they refer to valid objects by just doing a find() call.
How should I check if the strings are in the correct format? I've seen some regexs that check if the string is a 24 character string and stuff like that - seems like a hack. Is there an internal validator on the ObjectId? I couldn't figure out how to use it. Thanks so much!
The text was updated successfully, but these errors were encountered: