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
Related
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 am using mongodb triggers for automated update of courses_count in student collection.
My student collection is as:
Validation rule for student collection is defined as:
{
$jsonSchema: {
required: [
'name',
'email',
'password',
'dob',
'address'
],
properties: {
name: {
bsonType: 'string'
},
email: {
bsonType: 'string'
},
password: {
bsonType: 'string'
},
dob: {
bsonType: 'date'
},
address: {
bsonType: 'string'
},
courses_count: {
bsonType: [
'int',
'double',
'decimal'
]
}
courses: {
bsonType: 'array',
items: {
required: [
'_id',
'is_completed',
'is_certified'
],
properties: {
_id: {
bsonType: 'objectId'
},
name: {
bsonType: 'string'
},
is_free: {
bsonType: 'bool'
},
is_completed: {
bsonType: 'bool'
},
is_certified: {
bsonType: 'bool'
},
}
}
}
}
}
}
You can clearly see, I've defined courses_count to be int,doubleordecimal
I have defined courses_count_trigger in mongodb atlas as:
exports = async function(changeEvent) {
const { fullDocument } = changeEvent;
const mongodb = context.services.get("vidly");
const docId = changeEvent.documentKey._id;
var courses_count= 0;
if(fullDocument.courses){
courses_count=fullDocument.courses.length;
}
return mongodb.db("coursera").collection("student").updateOne({_id:docId},{ $set:{courses_count: courses_count}});
}
It's fine when there are some courses in my student collection.
It updates correctly using fullDocument.courses.length.
But when there are no courses , it fails to update the document.
i.e. it fails the validation.
I have also checked:
typeof(fullDocument.courses.length) gives number.
typeof(0) is obviously number.
Why does it fails validation? Please help.
this is error return in postman when i try to archive a record in my Sails backend.
UsageError: Invalid initial data for new records.\nDetails:\n Could not use one of the provided new records: Missing value for required attribute id. Expected a string, but instead, got: undefined\n [?] See https://sailsjs.com/support for help
Please somebody know what this error means? Thanks in advance.
Thanks for your response
My code:
- In controller:
try {
await Laboratory.archive({id: inputs.id});
} catch (error) {
console.log('Error-6 CORE-DELETE_LABORATORY:', error)
exits.failed(`Error-6 CORE-DELETE_LABORATORY: ${error}${inputs.id}`)}
In file config/models.js:
module.exports.models = {
migrate: 'alter',
fetchRecordsOnUpdate: true,
fetchRecordsOnCreate: true,
fetchRecordsOnCreateEach: true,
attributes: {
createdAt: { type: 'ref', columnType: 'datetime', autoCreatedAt: true, },
updatedAt: { type: 'ref', columnType: 'datetime', autoUpdatedAt: true, },
id: { type: 'string', columnName: '_id' },
},
dataEncryptionKeys: {
default: 'dRYQHBf8Zpza2vMS5BB3qcSiLspJP4BG37I2JkP2yYw='
},
cascadeOnDestroy: true
};
Laboratory model:
module.exports = {
attributes: {
type: {
type: 'string',
isIn: ['INSIDE', 'OUTSIDE'],
required: true,
},
raisonSocial: {
type: 'string',
required: true,
unique: true,
},
city: {
type: 'string'
},
address: {
type: 'string'
},
email: {
type: 'string'
},
neighborhood: {
type: 'string'
},
contacts: {
type: 'string'
},
logo: {
type: 'string'
},
lat: {
description: 'Latitude',
type: 'number'
},
long: {
description: 'Longitude',
type: 'number'
},
website: {
type: 'string',
defaultsTo: ''
},
subdomain: {
type: 'string',
unique: true,
required: true,
},
mobileMoney: {
type: 'string'
},
bank: {
type: 'string',
defaultsTo: ''
},
bankAccountID: {
type: 'string',
defaultsTo: ''
},
validated : {
type: 'boolean',
defaultsTo : false
},
f_establishment: {
model: 'establishment'
},
director: {
description: 'Chef of laboratory id',
type: 'json',
example: '{name, phone, role}',
required: true,
}
},
customToJSON () {
if (this.logo) {
this.logo = `${process.env.BASE_URL}/avatar/${this.logo}`
}
return this
}
};
Thanks.
Sails throws UsageError when we use a db method in an incorrect way. To be more precise, this is what Sails has in its documentation.
When an error has name: 'UsageError', this indicates that a Waterline
method was used incorrectly, or executed with invalid options (for
example, attempting to create a new record that would violate one of
your model's high-level validation rules.)
https://sailsjs.com/documentation/concepts/models-and-orm/errors#?usage-errors
To give you a simple example, if you have a db query with limit parameter and you start passing string values for that parameter, Sails with start throwing UsageError.
In your case, things should be self explanatory from the error detail itself. Your code flow is getting undefined for inputs.id when it tries to run Laboratory.archive({id: inputs.id}) but id is expected to be a string if you see config/models.js.
Just do a basic debugging to see why inputs.id is coming as undefined and solve that issue, and you should be good to go.
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
});
I want to create a model like below. users model having attribute agreements of type array.I was not able to find a example in waterline where attributes type is an array of object. Please advise
`
module.exports = {
attributes: {
userName: {
type: "string",
unique: true,
required: true
},
Name: {
type: "string",
required: true,
minLength: 2
},
phone: {
type: "string",
required: true
},
password: {
type: "string",
minLength: 6
},
roles: {
type: "array",
required: true,
enum: ['Admin', 'User']
},
agreements: {
type : "array",
agreement :{
version : "string",
dateSigned :"date",
}
},
`
Use one to many association.
Assume that your model is Model.js
agreements: { collection: 'Agreement', via : 'model' }
Create Agreement.js in models
module.exports: {
attributes: {
model : { model: 'Model' },
version : { type: 'string' },
dateSigned : { type: 'datetime' }
}
}
See this documentation.