I'm following a course from mongodb university to learn new features in the release 3.6, and I'm unable to resolve why my validator is invalid.
This is how I created the collection:
db.getSiblingDB("TSA").createCollection("claims", {
validator: {
$jsonSchema: {
bsonType: "object",
properties: {
_id: { },
airportCode: { type: "string", minLength: 3 },
airportName: { type: "string" },
airlineName: { type: "string", minLength: 5 },
claims: {
bsonType: "object",
properties: {
itemCategory: { bsonType: "array", maxItems: 3 },
amount: { type: "string", pattern: "^\$.*" }
}
}
},
required: ["airportCode", "airlineName", "claims"],
additionalProperties: false
}
}
})
Then, I try to insert this object:
db.getSiblingDB("TSA").claims.insertOne({
"airportCode": "ABE",
"airportName": "Lehigh Valley International Airport, Allentown",
"airlineName": "MongoAir",
"claims": {
"claimType": "Property Damage",
"claimSite": "Checked Baggage",
"itemCategory": [ "Sporting Equipment & Supplies" ],
"amount": "$180.00"
}
})
Getting the following error:
WriteError({
"index" : 0,
"code" : 121,
"errmsg" : "Document failed validation",
"op" : {
"_id" : ObjectId("5a705318d3d6c18337f07282"),
"airportCode" : "ABE",
"airportName" : "Lehigh Valley International Airport, Allentown",
"airlineName" : "MongoAir",
"claims" : {
"claimType" : "Property Damage",
"claimSite" : "Checked Baggage",
"itemCategory" : [
"Sporting Equipment & Supplies"
],
"amount" : "$180.00"
}
}
})
My question is, is there some way to debug the validator like "property X must be Y type" instead of getting a generic "Document failed validation"?
As of MongoDB 3.6, there is no feedback mechanism that would inform what part of a document failed validation during a server-side check. A corresponding feature request is open: SERVER-20547: Expose the reason an operation fails document validation. For now, it is left to the application code to perform its own validation if detailed feedback is required.
If you use regex pattern string, backslash itself must be escaped too:
db.getSiblingDB("TSA").createCollection("claims", {
validator: {
$jsonSchema: {
bsonType: "object",
properties: {
_id: { },
airportCode: { type: "string", minLength: 3 },
airportName: { type: "string" },
airlineName: { type: "string", minLength: 5 },
claims: {
bsonType: "object",
properties: {
itemCategory: { bsonType: "array", maxItems: 3 },
amount: { type: "string", pattern: "^\\$.*" }
}
}
},
required: ["airportCode", "airlineName", "claims"],
additionalProperties: false
}
}
})
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 try to insert multiple documents into my MongoDB collection, but whatever I do, I get a duplicate error. I made sure that there should be no duplicates possible by dropping the whole collection.
I tried it with .insertMany(), .save(), .create() - none of them do work. Though the docs get inserted, I still get the duplicate error 11000.
My function to insert the docs:
Words.prototype.addManyGeneralWordsEN = async function(words) {
await generalWordEN.create(words).then((res) => {
console.log(res)
})
.catch((err) => {
console.log(err.code)
})
}
// add words to database
await this.addManyGeneralWordsEN(wordsToAdd)
My schema:
const generalWordENSchema = new mongoose.Schema(
{
german: {
type: String,
required: true
},
english: {
type: String,
required: true
},
partOfSpeech: {
required: true,
type: String
},
example: {
default: null,
type: String,
},
defintion: {
default: null,
type: String,
},
image: {
default: null,
type: String,
},
audio: {
default: null,
type: String,
},
level: {
default: null,
type: Number,
},
}
)
generalWordENSchema.index({ german: 1, english: 1, partOfSpeech: 1}, { unique: true })
module.exports = generalWordENSchema
My sample data:
[
{
"english": "clothes",
"german": "Kleidung",
"partOfSpeech": "noun",
"example": "My wife's wardrobe is filled with beautiful clothes.",
"definition": "",
"image": "",
"audio": "",
"level": ""
},
{
"english": "men's clothing",
"german": "Herrenbekleidung",
"partOfSpeech": "noun",
"example": "Men's clothing is on the second floor.",
"definition": "",
"image": "",
"audio": "",
"level": ""
}
]
The problem is probably on this line
generalWordENSchema.index({ german: 1, english: 1, partOfSpeech: 1}, { unique: true })
You created an index for the collection and used partOfSpeech as unique, but you have two documents with the same value noun.
It should work if you change it to:
generalWordENSchema.index({ german: 1, english: 1 }, { unique: true });
You also have a typo on the Schema declaration that might cause you different issues. You typed defintion instead of definition.
I have been searching for some hours how to make the ISBN field unique and haven't found a solution. Creating an index gives me the following error. I still didn't understand how these indexes work - I am in the process of learning. If you come with a quick solution let me know!
Attempt to create an index
db.books.createIndex( {ISBN : 1} , {unqiue : true} )
Error
/* 1 */
{
"ok" : 0.0,
"errmsg" : "Error in specification { key: { ISBN: 1.0 }, name: \"ISBN_1\", unqiue: true } :: caused by :: The field 'unqiue' is not valid for an index specification. Specification: { key: { ISBN: 1.0 }, name: \"ISBN_1\", unqiue: true }",
"code" : 197,
"codeName" : "InvalidIndexSpecificationOption"
}
Schema
db.createCollection("books", {
validator: {
$jsonSchema: {
bsonType: "object",
required: [
"ISBN",
"title"
],
properties: {
_id: {},
ISBN: {
bsonType: "string",
// make this unique
},
title: {
bsonType: "string",
},
},
},
},
});
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.