I’m using an Atlas based mongodb instance and fastify for backend. I’m also using @sinclair/typebox to generate JSON Schemas for data validation. Normally, I use these schemas to validate input messages but I now want to reuse them as validators for MongoDB collections too.
I have something like this:
await database.command({
collMod: 'users',
validator: {
$jsonSchema: UserSchema,
},
});
And also, I have examples set for some of the fields. e.g.:
export const HandleSchema = Type.RegEx(/^[a-zA-Z0-9_-]{1,24}$/, {
examples: ['harry-potter', 'jane-doe-99'],
title: 'Handle',
// ...
});
export const UserSchema = Type.Object(
{
_id: HandleSchema,
// ...
},
{ additionalProperties: false },
);
However, I’m getting this error while trying to apply this validator:
Parsing of collection validator failed :: caused by :: Unknown $jsonSchema keyword: examples
Which means the examples
keyword is not recognized by MongoDB; and unfortunately looks like this happens in server side. Looks like they dared to ignore the behavior suggested by the spec. I’m also seeing a flag that can be used to ignore unknown keywords, but unfortunately, setParameter
doesn’t work with atlas.
Now, at least I should be able to remove examples
somehow from typebox or ajv. I tried Type.Strict(UserSchema)
and ajv.customOptions.keywords
set to ['examples']
(this probably is the inverse of what I want to achieve), but they didn’t work.
How do I ignore examples
field just for the mongodb schema? Or how do I fix this from MongoDB Atlas side (looks impossible)? Any other approach?
Thanks in advance.
2
Answers
Regardless of how much I dislike this approach, I went for a "temporary" solution.
Since the end result of a json schema -- as mongodb sees it -- is nothing more than a plain old javascript object. So I wrote a utility function to recursively strip-out the unnecessary fields.
This is not completely accurate, especially the type definitions; I'll keep improving it. However, it does what I want.
Looks like
examples
was not the only field that mongodb reject.And I'm using the stripped version only for the MondoDB.
I am in the process of doing something very similar to what you are doing. Have you tried using an
Unsafe
type. As described in the documents:So in your case you could so something like this:
and then you can use it like this:
Now I am not 100% certain this is the correct way of handling things as I’m still learning the library, but by the looks of it, it seems to do what you described. Unless I misunderstood your question.
You said you wanted to reuse the schema both for ajv and mongodb. I am not sure if you can use the exact same schema object to do both, but what you can easily do is make a wrapper function that outputs 2 schemas, for ajv and mongodb, depending on some parameter you pass to it.
Personally I think that would be a better implementation than writing a recursive function that strips out unnecessary keys.