{
$jsonSchema: {
bsonType: "object",
required: ["firstName", "lastName", "email", "destination"],
properties: {
firstName: {
bsonType: "string",
description: "First name is required!"
},
lastName: {
bsonType: "string",
description: "Last name is required!"
},
email: {
bsonType: "string",
pattern: "^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$",
description: "Email is required"
},
destination: {
bsonType: "string",
description: "Destination is require!"
}
}
}
}
In the above $jsonSchema, I attempt to use pattern as part of the schema specification
However, me existing ✉️ data fails validation inside of Compass.
This same pattern works just fine on client-side ReactJS form validation, so IK that the pattern itself is good.
However, something must be amiss with how we use this in $jsonSchema.
JSON Schema is encoded in JSON, and as such, strings need to be escaped.
This includes \ which must become \\, so where in your regex you have \., you need to escape it to become \\..
Having said that, as I don't have examples of your JSON data (and the email) you're trying to valid, I'm assuming what you've said is correct regarding the regular expression being sufficient for you elsewhere.
Related
Currently having hard time setting up my end points clerk to hasura.
I am absolute new to this platform specially at GraphiQL and just following documentations and youtube video
What I am trying to do is import/insert specific data i neeed only from clerk. Here's the sample query variables:
{
"data": {
"birthday": "",
"created_at": 1654012591514,
"email_addresses": [
{
"email_address": "example#example.org",
"id": "idn_29w83yL7CwVlJXylYLxcslromF1",
"linked_to": [],
"object": "email_address",
"verification": {
"status": "verified",
"strategy": "ticket"
}
}
],
"external_accounts": [],
"external_id": "567772",
"first_name": "Example",
"gender": "",
"id": "user_29w83sxmDNGwOuEthce5gg56FcC",
"last_name": "Example",
"last_sign_in_at": 1654012591514,
"object": "user",
"password_enabled": true,
"phone_numbers": [],
"primary_email_address_id": "idn_29w83yL7CwVlJXylYLxcslromF1",
"primary_phone_number_id": null,
"primary_web3_wallet_id": null,
"private_metadata": {},
"profile_image_url": "https://www.gravatar.com/avatar?d=mp",
"public_metadata": {},
"two_factor_enabled": false,
"unsafe_metadata": {},
"updated_at": 1654012591835,
"username": null,
"web3_wallets": []
},
"object": "event",
"type": "user.created"
}
What I only need to this object is content inside of the "data" is: created_at, first_name, user_id, updated_at, profile_image_url
The GraphiQL Query I did is:
mutation CreateUser(
$created_at: String,
$first_name: String,
$user_id: String,
$updated_at: String,
$profile_image_url: String
)
{
insert_users_one(object:
{
created_at: $created_at,
first_name: $first_name,
user_id: $user_id,
updated_at: $updated_at,
profile_image_url: $profile_image_url,
}) {
created_at
first_name
user_id
updated_at
profile_image_url
}
}
Which throwing error of:
{
"errors": [
{
"extensions": {
"code": "validation-failed",
"path": "$"
},
"message": "unexpected variables in variableValues: object, type, data"
}
]
}
I tried using other method like this:
mutation CreateUser($data: users_insert_input!) {
insert_users_one(object: $data) {
created_at
first_name
user_id
updated_at
profile_image_url
}
}
But it is still having error because of object and type fields
{
"errors": [
{
"extensions": {
"code": "validation-failed",
"path": "$"
},
"message": "unexpected variables in variableValues: object, type"
}
]
}
Here's a sample of GraphQL type:
//is this how you break things down?
type Mutation {
data(
created_at: Int
first_name: String
id: String
updated_at: Int
profile_image_url: String
): Data
}
//this is what i will send in the database, things that I only need
type Verification {
status: String
strategy: String
}
type EmailAddresses {
email_address: String
id: String
object: String
verification: Verification
linked_to: [String]
}
type Data {
birthday: String
created_at: Int
external_id: String
first_name: String
gender: String
id: String
last_name: String
last_sign_in_at: Int
object: String
password_enabled: Boolean
primary_email_address_id: String
primary_phone_number_id: String
primary_web3_wallet_id: String
profile_image_url: String
two_factor_enabled: Boolean
updated_at: Int
username: String
web3_wallets: [String]
phone_numbers: [String]
external_accounts: [String]
email_addresses: [EmailAddresses]
}
type AutogeneratedMainType {
object: String
type: String
data: Data
}
I was expecting based on documents, It will ignore aren't included data.
Visit Github Discussions here
Context about the error
This is error you are receiving is based on this graphql spec - https://spec.graphql.org/June2018/#sec-Input-Objects . More over there is also a different spec for validation against variables here - https://spec.graphql.org/June2018/#sec-All-Variables-Used
TLDR; Using variable which isn’t defined in operation, will result into “unexpected variableValues” error. In your case apart from data , you have type and object as variables in your query variables object which is not defined in operation itself. Remember that query variables is an “object” expecting the variable key-values in it.
Workaround
Cleanest way to do this is to sanitize your object (which you will pass in query variables) by either creating a new object from it and passing data to it or either you remove the unnecessary fields from it which are not defined in operation. You could just delete the properties of that object. Consider yourObject containing data,type and object fields. Then you can do delete yourObject.type and delete yourObject.object. And then pass it.
This workaround is intended for client side code. But there's no exception for graphiQL explorer as that error would be thrown upon undefined variables in operation. If trying via graphiQL explorer, you would manually need to not pass those variables in query variables scope.
Conclusion
This behavior is in compliant with this graphql spec and not with Hasura directly, so we would suggest you to go through those graphql spec links and understand the aspect of it.
Let's say i have a collection that looks like this
$jsonSchema: {
bsonType: "object",
required: [ "Author", "Draft"],
properties: {
Tittle: {
bsonType: "string",
},
LastUpdated: {
bsonType: "date",
},
Author: {
bsonType: "string",
},
Draft: {
bsonType: "string"
}
}
}
The tittle, Publisher and Author fields, are almost never changed
The draft field can get "large" with thousands of words, when the author is working on it, it constantly(every few seconds if changed) saves the draft version to the Database
What would be the effective options for me?
I'm using Compass's validation tab to manually enter the $jsonSchema validation below.
Unfortunately it keeps showing the error "Unknown $jsonSchema keyword: geometry"
Not sure why this error is showing, since geometry is being used as a key.
Any advice on how I can correct this please?
{
$jsonSchema: {
bsonType: "object",
required: ["properties.Name", "properties.Country", "geometry.type", "geometry.coordinates"],
properties:{
Country: {
bsonType: "string",
description: "Must be supplied"
},
Name: {
bsonType: "string",
description: "Must be supplied"
},
description: {
bsonType: "string",
description: "Optional description"
}
},
geometry: {
type: {
bsonType: "string",
enum: ["Point"],
description: "Must be Point"
},
coordinates: {
bsonType: ["double"],
description: "Longitude, Latitude"
}
},
datePosted: {
bsonType: "date",
description: "Auto-added field"
},
image: {
bsonType: "string",
description: "URL of image location"
}
}
}
The JSON Schema you have supplied doesn't look quite right. The error about the unknown "geometry" keyword is because that attribute should describe one of your properties. The structure of the JSON Schema file is rigid and follows a tight (but admittedly confusing) spec.
I see a few things wrong with the schema you supplied:
The array of required properties should list the keys within the
properties object. So in your case, it should be something like
required: ["Name", "Country", "geometry"]
The geometry, datePosted, and image objects need to be placed inside the properties object.
The description of the geometry object must itself be another JSON Schema (it's a recursive pattern).
What is the geometry type? You have defined it as a string and as an enum with only one possible option ("Point"). Enum's only make sense if you provide multiple options, and their values would supersede the data type specified.
The code below is tested on MongoDB Compass:
{
$jsonSchema: {
bsonType: 'object',
required: [
'properties.Name',
'properties.Country',
'geometry.type',
'geometry.coordinates'
],
properties: {
Country: {
bsonType: 'string',
description: 'Must be supplied'
},
Name: {
bsonType: 'string',
description: 'Must be supplied'
},
description: {
bsonType: 'string',
description: 'Optional description'
},
geometry: {
type: 'object',
properties: {
type: {
'enum': [
'Point'
],
description: 'Must be Point'
},
coordinates: {
bsonType: [
'object'
],
description: 'Contains Longitude, Latitude',
properties: {
longitude: {
type: 'number',
description: 'Decimal representation of longitude'
},
latitude: {
type: 'number',
description: 'Decimal representation of latitude'
}
}
}
}
},
datePosted: {
bsonType: 'date',
description: 'Auto-added field'
},
image: {
bsonType: 'string',
description: 'URL of image location'
}
}
}
}
Have a look at the example in the docs: https://docs.mongodb.com/manual/core/schema-validation/
geometry is innerjson object so you need to mention what type of this innerjson object
geometry:{
bsonType:'object'} then mention required fields
I am learning the official GraphQl doc.
When I come to the chapter introspection link here
I have encounter something called wrapper type.
input:
{
__type(name: "Droid") {
name
fields {
name
type {
name
kind
}
}
}
}
Output:
{
"data": {
"__type": {
"name": "Droid",
"fields": [
{
"name": "id",
"type": {
"name": null, # here
"kind": "NON_NULL"
}
},
{
"name": "name",
"type": {
"name": null, # here
"kind": "NON_NULL"
}
},
{
"name": "friends",
"type": {
"name": null, # here
"kind": "LIST"
}
},
{
"name": "friendsConnection",
"type": {
"name": null, # here
"kind": "NON_NULL"
}
},
{
"name": "appearsIn",
"type": {
"name": null, # here
"kind": "NON_NULL"
}
},
{
"name": "primaryFunction",
"type": {
"name": "String", # normal here
"kind": "SCALAR"
}
}
]
}
}
}
The article claims the name of those type of fields of type is NULL because it's a " wrapper" type of kind NON_NULL
Could someone explain what is exactly a wrapper type? Better provide an example or code to explain why primaryFunction has a name but others do not.
From the spec:
All of the types so far are assumed to be both nullable and singular: e.g. a scalar string returns either null or a singular string.
A GraphQL schema may describe that a field represents list of another types; the List type is provided for this reason, and wraps another type.
Similarly, the Non-Null type wraps another type, and denotes that the resulting value will never be null (and that an error cannot result in a null value).
These two types are referred to as “wrapping types”; non‐wrapping types are referred to as “named types”. A wrapping type has an underlying named type, found by continually unwrapping the type until a named type is found.
A wrapping type wraps another type, which itself may also be a wrapping type. However, as you "unwrap" each wrapping type, eventually you have to hit a named type that all those wrapping types are associated with. In other words, wrapping types can never be used by themselves. A wrapping type always has exactly one named type it's associated to.
In introspection, to determine what type the wrapping type is wrapping, use the ofType field:
{
__schema {
types {
name
ofType {
name
}
}
}
}
You can add additional levels to potentially "unwrap" types further:
{
__schema {
types {
name
ofType {
name
ofType {
name
}
}
}
}
}
As to why introspection doesn't show a name for these types, it's because the spec specifically prohibits it. Take a look at the section for the List type:
Lists represent sequences of values in GraphQL. A List type is a type modifier: it wraps another type instance in the ofType field, which defines the type of each item in the list.
Fields
kind must return __TypeKind.LIST.
ofType: Any type.
All other fields must return null.
Here is some snippet from a tutorial I have done the other day. It represents a type wrapped with GraphQLNonNull operator (it's for the server side):
const ContestStatusType = require('./contest-status')
const NameType = require('./name')
module.exports = new GraphQLObjectType({
name: 'ContestType',
fields: {
id: { type: GraphQLID },
description: { type: GraphQLString },
status: { type: new GraphQLNonNull(ContestStatusType) },
createdAt: { type: new GraphQLNonNull(GraphQLString) },
createdBy: { type: new GraphQLNonNull(GraphQLString) },
names: {
type: new GraphQLList(NameType),
resolve(obj, args, { loaders, pgPool }) {
return loaders.namesForContestIds.load(obj.id);
return pgdb(pgPool).getNames(obj)
}
}
}
});
I have two schemas with 1 to N relation. one is book and the other author.
I have crated three files names: book.js, genre.js and author.js below. As you see, I have referenced in the book the genre and author from other files.
author: {
$ref: "./models/author.js"
},
and
"genre" : {
$ref: "./models/genre.js",
description: "must be a string and is required"
}
However, When I issue that in mongo> i get the following:
{
"ok" : 0,
"errmsg" : "$jsonSchema keyword '$ref' is not currently supported",
"code" : 9,
"codeName" : "FailedToParse"
}
I was wondering How I could do that please?
// book.js
var book = {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "title", "author", "summary", "isbn", "genre" ],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required"
},
author: {
$ref: "./models/author.js"
},
isbn: {
bsonType: "int",
minimum: 2017,
maximum: 3017,
exclusiveMaximum: false,
description: "must be an integer in [ 2017, 3017 ] and is required"
},
"summary" : {
bsonType: "string",
description: "must be a string and is required"
},
"genre" : {
$ref: "./models/genre.js"
}
}
}
}
};
module.exports = book;
//genre.js
var genre = {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "name"],
properties: {
first_name: {
bsonType: "string",
size: 100,
description: "must be a string and is required"
},
url: {
bsonType: "string",
minLength:3,
maxLength:20,
description: "must be a string and size between [3, 100] is not required"
}
}
}
}
};
module.exports = genre;
//author.js
var Author = {
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "first_name", "family_name" ],
properties: {
first_name: {
bsonType: "string",
maxLength:100,
description: "must be a string and is required"
},
family_name: {
bsonType: "string",
maxLength:100,
description: "must be a string and is not required"
},
date_of_birth: {
bsonType: "int",
minimum: 0,
maximum: 2018,
exclusiveMaximum: false,
description: "must be an integer in [ 0, 3017 ] and is required"
},
date_of_death: {
bsonType: "int",
minimum: 0,
maximum: 2018,
exclusiveMaximum: false,
description: "must be an integer in [ 0, 2018 ] and is required"
}
}
}
}
};
module.exports = Author;
It seems the Manual References does not work:
$jsonSchema: {
bsonType: "object",
required: [ "title", "author_id", "summary", "isbn", "genre" ],
properties: {
title: {
bsonType: "string",
description: "must be a string and is required"
},
author_id: {
bsonType: ObjectId(),
description: "must be a string and is required"
},
isbn: {
as
{
"ok" : 0,
"errmsg" : "$jsonSchema keyword 'bsonType' must be either a string or an array of strings",
"code" : 14,
"codeName" : "TypeMismatch"
}
"$jsonSchema keyword '$ref' is not currently supported",
As per the error message you encountered, the implementation of JSON Schema does not (as at MongoDB 4.0) support references ($ref). Since $jsonSchema is being validated on the database server a relative file path isn't appropriate; you should instead inline the required schema validation rules.
If you want more flexibility you could look for a validation library you can use in your application code. There are several JSON Schema packages on NPM as well as alternative approaches such as Object-Document Mappers (for example, Mongoose).
It seems the Manual References does not work
bsonType: ObjectId(),
The ObjectId() usage here isn't valid JSON. You need to specify a string value with the BSON type: bsonType: "objectId".
For more information see $jsonSchema Extensions and Omissions in the MongoDB documentation for your server version.
Thank you very much. bsonType: "objectId". To be honest with you, I don't like using Mongoose. Using manual referencing:
original_author_id = ObjectId()
db.author.insert({
"_id": original_author_id,
first_name: "ghadamali",
family_name: "sarami",
date_of_birth: NumberInt(1944)
});
original_genre_id = ObjectId()
db.genre.insert({
"_id": original_genre_id,
name: "action",
url: "www.action.com"
});
db.book.insert({
title:"az range gol",
author_id: original_author_id,
summary: "shekle senasi shahname",
isbn: NumberInt(12312),
genre:original_genre_id
});