Why do I have a fail validation with mongodb? - javascript

I'm new on mongodb, I have read documentation and I try to insert a document page with referenced id's of other documents but I have a validation fail.
That's my schema validation rules :
db.createCollection("page", {
capped: true,
size: 4500000000,
max: 6,
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "title", "url", "elements" ],
additionalProperties: false,
properties: {
title: {
bsonType: "object",
required: [ "content_id" ],
properties: {
content_id: {
bsonType: "objectId"
}
}
},
url: {
bsonType: "string"
},
elements: {
bsonType: "array",
items: {
bsonType: "object",
required: [ "order" , "element_id" ],
properties: {
order: {
bsonType: "int"
},
element_id: {
bsonType: "objectId"
}
}
}
}
}
}
}
});
And this is what i try to insert (i add in variable the futur id Object and variable content and document already have the id's i need)
var page1 = ObjectId();
db.page.insertOne(
{
"_id": page1,
"title": {
"content_id": content5
},
"url": "/home",
"elements": [
{
"order": 1,
"element_id": element1
},
{
"order": 2,
"element_id": element2
},
{
"order": 3,
"element_id": element3
},
{
"order": 4,
"element_id": element4
}
]
}
);
Please why do I have this error? I don't understand what the problem is, is this schema good with what I'm trying to insert?
2020-04-07T18:55:35.513+0200 E QUERY [js] WriteError({
"index" : 0,
"code" : 121,
"errmsg" : "Document failed validation",
"op" : {
"_id" : ObjectId("5e8c72698d808f037e6adede"),
"title" : {
"content_id" : ObjectId("5e8c72128d808f037e6aded6")
},
"url" : "/home",
"elements" : [
{
"order" : 1,
"element_id" : ObjectId("5e8c724d8d808f037e6adeda")
},
{
"order" : 2,
"element_id" : ObjectId("5e8c724d8d808f037e6adedb")
},
{
"order" : 3,
"element_id" : ObjectId("5e8c724d8d808f037e6adedc")
},
{
"order" : 4,
"element_id" : ObjectId("5e8c724d8d808f037e6adedd")
}
]
}
}) :
WriteError({
"index" : 0,
"code" : 121,
"errmsg" : "Document failed validation",
"op" : {
"_id" : ObjectId("5e8c72698d808f037e6adede"),
"title" : {
"content_id" : ObjectId("5e8c72128d808f037e6aded6")
},
"url" : "/home",
"elements" : [
{
"order" : 1,
"element_id" : ObjectId("5e8c724d8d808f037e6adeda")
},
{
"order" : 2,
"element_id" : ObjectId("5e8c724d8d808f037e6adedb")
},
{
"order" : 3,
"element_id" : ObjectId("5e8c724d8d808f037e6adedc")
},
{
"order" : 4,
"element_id" : ObjectId("5e8c724d8d808f037e6adedd")
}
]
}
})
WriteError#src/mongo/shell/bulk_api.js:458:48
mergeBatchResults#src/mongo/shell/bulk_api.js:855:49
executeBatch#src/mongo/shell/bulk_api.js:919:13
Bulk/this.execute#src/mongo/shell/bulk_api.js:1163:21
DBCollection.prototype.insertOne#src/mongo/shell/crud_api.js:264:9
#(shell):1:1
Thank you for your answers

Okay, I got the solution, the problem was the additional rule Properties. So if it's on false, you have to add the _id property before inserting data because it considers _id as an additional property.
The bsonType: "int" can also make an error, so use number.
So with this validator rule i can insert my data ->
db.createCollection("page", {
capped: true,
size: 4500000000,
max: 6,
validator: {
$jsonSchema: {
bsonType: "object",
required: [ "_id", "title", "url", "elements" ],
additionalProperties: false,
properties: {
_id: {
bsonType: "objectId"
},
title: {
bsonType: "object",
required: [ "content_id" ],
properties: {
content_id: {
bsonType: "objectId"
}
}
},
url: {
bsonType: "string"
},
elements: {
bsonType: "array",
items: {
bsonType: "object",
required: [ "order" , "element_id" ],
properties: {
order: {
bsonType: "number"
},
element_id: {
bsonType: "objectId"
}
}
}
}
}
}
}
});

Related

AJV if-then-else conditional type based on enum

I've searched examples of using if-then-else in AJV schemas but haven't found a specific case where the property type and required list change based on the value of another property.
Case:
I need to upgrade userSchema so that if property role = superuser, then customer_id is both nullable and not required.
const userSchema: Schema<UserItem> = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
required: ['id', 'email', 'customer_id'],
additionalProperties: false,
properties: {
id: {
type: 'string',
format: 'uuid'
},
email: {
type: 'string',
format: 'email'
},
customer_id: {
type: 'string',
format: 'uuid'
},
role: {
anyOf: [
{ type: 'null' },
{ enum: Object.values(UserRole) }
]
}
}
}
I tried...
const userSchemaNullableCustomerId: Schema<UserItem> = {
...userSchema,
if: {
properties: {
role: { const: UserRole.Superuser }
}
},
then: {
properties: {
customer_id: {
anyOf: [
{ type: 'null' },
{ type: 'string', format: 'uuid' }
]
}
},
not: {
required: ['customer_id']
}
}
}
but it still complains that data.customer_id should be string. How can this be solved?
The following should be true:
// Valid
{
"id": "id",
"email": "foo#bar.com",
"role": "superuser",
"customer_id": null
},
{
"id": "id",
"email": "foo#bar.com",
"role": "superuser"
},
{
"id": "id",
"email": "foo#bar.com",
"role": "null",
"customer_id": 'some-uuid...'
},
{
"id": "id",
"email": "foo#bar.com",
"role": "user",
"customer_id": 'some-uuid...'
}
// Invalid
{
"id": "id",
"email": "foo#bar.com",
"role": "user",
"customer_id": null
},
{
"id": "id",
"email": "foo#bar.com",
"role": "user"
},
{
"id": "id",
"email": "foo#bar.com",
"role": "superuser",
"customer_id": 'nonUuidString'
}
After much experimentation, I discovered the trick is that the customer_id property has to be initialized as empty and the role property requires a dependency check.
...
properties: {
id: {
type: 'string',
format: 'uuid'
},
email: {
type: 'string',
format: 'email'
}
customer_id: {},
role: {
anyOf: [
{ type: 'null' },
{ enum: Object.values(UserRole) }
]
}
},
if: {
dependencies: { role: ['role'] },
properties: { role: { const: UserRole.Superuser } }
},
then: {
properties: { customer_id: { anyOf: [{ type: 'null' }, { type: 'string', format: 'uuid' }] } }
},
else: {
properties: { customer_id: { type: 'string', format: 'uuid' } }
}

jsonschema mongodb not validate from .js file

I have mongo.js commands to create collection, here is in my .js file:
let organizationSchema = {
bsonType: "object",
properties: {
name: {
bsonType: "string",
description: "must be a string and required"
},
active: {
bsonType: "bool",
},
location: {
bsonType: "string",
},
contactInfo: {
// this one doest working for validate
pattern: "/^\+?\d+(?:-\d+)*(?:\(\d+\)-\d+)*$/"
},
createdBy: {
bsonType: "string",
},
createdAt: {
bsonType: "date",
},
updatedAt: {
bsonType: "date",
},
deletedAt: {
bsonType: "date",
},
}
}
db.runCommand( { collMod: "organizations", validator:{ $jsonSchema: organizationSchema }, validationLevel: "strict"} )
db.organizations.createIndex( { "name": 1, "createdBy": 1, "location": 1, "active": 1} )
then I run mongo "mongodb+srv://url" --username dev -p 'dev' < mongo.js
on the contactInfo I do pattern for validation phone number, but when I insert data on my MongoDB Client, with invalid phone number, it was inserted, is that something wrong on that syntax on my js should I use strings on each keys there ??
const r = /^\+?\d+(?:-\d+)*(?:\(\d+\)-\d+)*$/;
console.log(r.test("+1110988888"))
console.log(r.test("zzzzuuuu"))

How remove data from an array in aggrigation whithout disturbing outside data in mongodb

Here I am trying to get entire data but if date less then current then do not fetch that date from the database.
{
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ab5"),
"highlights" : [
"highlights-1",
],
"notes" : [
"Listen"
],
"soldout" : false,
"active" : false,
"operator" : ObjectId(""),
"title" : "2D1N Awesome trip to Knowhere 99",
"destinations" : [
{
"coordinatesType" : "Point",
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ab6"),
}
],
"difficulty" : "Easy",
"duration" : {
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ab7"),
"days" : NumberInt(2),
"nights" : NumberInt(1)
},
"media" : {
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ab8"),
"images" : [
],
"videos" : [
]
},
"description" : "Surrounded ",
"inclusions" : [
{
"_id" : ObjectId(""),
"text" : "Included"
}
],
"itinerary" : "Surrounded .",
"thingsToCarry" : [
{
"_id" : ObjectId(""),
"text" : "Yourself"
}
],
"exclusions" : [
{
"_id" : ObjectId(""),
"text" : "A Lot"
}
],
"policy" : "Fully refundable 7777 Days before the date of Experience",
"departures" : [
{
"dates" : [
ISODate("2019-11-19T02:44:58.989+0000"),
ISODate("2019-11-23T17:19:47.878+0000")
],
"_id" : ObjectId(""),
"bookingCloses" : "2 Hours Before",
"maximumSeats" : NumberInt(20),
"source" : {
"coordinatesType" : "Point",
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ac2"),
"code" : "code",
"name" : "Manali",
"state" : "Himachal Pradesh",
"region" : "North",
"country" : "India",
"coordinates" : [
23.33,
NumberInt(43),
NumberInt(33)
]
},
"pickupPoints" : [
{
"coordinatesType" : "Point",
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ac3"),
"name" : "name-3",
"address" : "address-3",
"time" : "time-3",
"coordinates" : [
23.33,
NumberInt(43),
NumberInt(33)
]
}
],
"prices" : {
"3" : NumberInt(5)
},
"mrps" : {
"3" : NumberInt(5)
},
"markup" : NumberInt(25),
"discount" : NumberInt(0),
"b2m" : {
"3" : NumberInt(5)
},
"m2c" : {
"3" : 6.25
},
"minimumOccupancy" : NumberInt(3),
"maximumOccupancy" : NumberInt(3)
}
],
"bulkDiscounts" : [
{
"_id" : ObjectId("5d6fad0f9e0dc027fc6b5ac4")
}
],
}
In this I am trying to get all the data except the date section should be different. Means I should get my output as below
{
"_id": "5d6fad0f9e0dc027fc6b5ab5",
"highlights": [
"highlights-1",
"highlights-2",
"highlights-3",
"highlights-4",
"highlights-5"
],
"notes": [
"Listen"
],
"soldout": false,
"active": false,
"operator": "5d5d84e8c89fbf00063095f6",
"title": "2D1N Awesome trip to Knowhere 99",
"destinations": [
{
"code": "code",
"name": "Manali",
"coordinates": [
23.33,
43,
33
]
}
],
"difficulty": "Easy",
"duration": {
"_id": "5d6fad0f9e0dc027fc6b5ab7",
"days": 2,
"nights": 1
},
"media": {
"_id": "5d6fad0f9e0dc027fc6b5ab8",
"images": [
],
"videos": []
},
"description": "Surrounded.",
"inclusions": [
{
"_id": "5d6fad0f9e0dc027fc6b5abe",
"text": "Included"
}
],
"itinerary": "Surrounded",
"thingsToCarry": [
{
"_id": "5d6fad0f9e0dc027fc6b5abf",
"text": "Yourself"
}
],
"exclusions": [
{
"_id": "5d6fad0f9e0dc027fc6b5ac0",
"text": "A Lot"
}
],
"policy": "Fully refundable 7777 Days before the date of Experience",
"departures": [
{
"dates": [
"2019-11-23T17:19:47.878Z"
],
"_id": "5d6fad0f9e0dc027fc6b5ac1",
"bookingCloses": "2 Hours Before",
"maximumSeats": 20,
"source": {
"code": "code",
"name": "Manali",
"coordinates": [
23.33,
43,
33
]
},
"pickupPoints": [
{
"coordinatesType": "Point",
"_id": "5d6fad0f9e0dc027fc6b5ac3",
"name": "name-3",
"address": "address-3",
"time": "time-3",
"coordinates": [
23.33,
43,
33
]
}
],
"mrps": {
"3": 5
},
"markup": 25,
"discount": 0,
"b2m": {
"3": 5
},
"m2c": {
"3": 6.25
},
"minimumOccupancy": 3,
"maximumOccupancy": 3
}
],
"bulkDiscounts": [
{
"_id": "5d6fad0f9e0dc027fc6b5ac4"
}
],
"url": "",
}
]
I mean to say that no difference in output except dates array. If dates are less than current date then no need to fetch else fetch from DB with filtered dates array.
If you use mongo 3.4> then you can try with $addFields and $filter:
myCollection.aggregate([
{$match: {
'departures.dates': {
$elemMatch: {$gt: new Date()}}
}
},
{$addFields: {
'departures.dates': {
$filter: {
input: '$departures.dates',
as: 'date',
cond: {
$gt: ['$$date', new Date()]
}
}
}
}}
])
I was missing one terms here that my documnet structure is like below
{
_id: ObjecId(),
departure: [{
dates: [Array]
}]
}
So, here is my solution in the below code
pipeline = [
{ $unwind: '$departures' },
{
$addFields: {
'departures.dates': {
$filter: {
input: '$departures.dates',
as: 'date',
cond: {
$gt: ['$$date', new Date()]
}
}
}
}
}
];

Mongodb $graphLookup build hierarchy [duplicate]

This question already has answers here:
MongoDB $graphLookup get children all levels deep - nested result
(2 answers)
Closed 3 years ago.
I have an output from mongodb $graphLookup aggregation:
db.getCollection('projects').aggregate([
{
$lookup: {
from: "projects",
localField: "_id",
foreignField: "parent",
as: "childrens"
}
}
])
{
"_id" : "1",
"name" : "Project1",
"parent" : null,
"childrens" : [
{
"_id" : "3",
"name" : "ProjectForId1",
"parent" : "1"
}
]
},
{
"_id" : "3",
"name" : "ProjectForId1",
"parent" : "1",
"childrens" : [
{
"_id" : "6",
"name" : "ProjectForId3",
"parent" : "3"
},
{
"_id" : "7",
"name" : "ProjectForId3",
"parent" : "3"
}
]
}
I need to build hierarchy from this output in javascript or if is possible directly from query so the final output should look like:
{
"_id" : "1",
"name" : "Project1",
"parent" : null,
"childrens" : [
{
"_id" : "3",
"name" : "ProjectForId1",
"parent" : "1",
"childrens" : [
{
"_id" : "6",
"name" : "ProjectForId3",
"parent" : "3"
},
{
"_id" : "7",
"name" : "ProjectForId3",
"parent" : "3"
}
]
}
]
}
Also if someone have a brave heart to help in one more case where the hierarchy will be created by filtering _id:
ex: For _id = "1" the output will be same as above but if _id is 3 the final output should look like:
{
"_id" : "3",
"name" : "ProjectForId1",
"parent" : "1",
"childrens" : [
{
"_id" : "6",
"name" : "ProjectForId3",
"parent" : "3"
},
{
"_id" : "7",
"name" : "ProjectForId3",
"parent" : "3"
}
]
}
Below solution is more or less the same as one of my past answers so you can get thorough explanation here
db.projects.aggregate([
{
$graphLookup: {
from: "projects",
startWith: "$_id",
connectFromField: "_id",
connectToField: "parent",
as: "children",
maxDepth: 4,
depthField: "level"
}
},
{
$unwind: "$children"
},
{
$sort: { "children.level": -1 }
},
{
$group: {
_id: "$_id",
children: { $push: "$children" }
}
},
{
$addFields: {
children: {
$reduce: {
input: "$children",
initialValue: {
currentLevel: -1,
currentLevelProjects: [],
previousLevelProjects: []
},
in: {
$let: {
vars: {
prev: {
$cond: [
{ $eq: [ "$$value.currentLevel", "$$this.level" ] },
"$$value.previousLevelProjects",
"$$value.currentLevelProjects"
]
},
current: {
$cond: [
{ $eq: [ "$$value.currentLevel", "$$this.level" ] },
"$$value.currentLevelProjects",
[]
]
}
},
in: {
currentLevel: "$$this.level",
previousLevelProjects: "$$prev",
currentLevelProjects: {
$concatArrays: [
"$$current",
[
{ $mergeObjects: [
"$$this",
{ children: { $filter: { input: "$$prev", as: "e", cond: { $eq: [ "$$e.parent", "$$this._id" ] } } } }
] }
]
]
}
}
}
}
}
}
}
},
{
$addFields: { children: "$children.currentLevelProjects" }
},
{
$match: {
_id: "1"
}
}
])
Last stage is supposed to be the filtering so you can get the data for any level of depth here.

How to implement hierarchical model in Sencha Touch

I have read many questions/answers and tutorials and I still fail to implement hierarchical model in Sencha Touch. The root model is Tag. Each Tag has many Items. Here is my model:
The root tag:
app.models.Tag = Ext.regModel("Tag", {
fields : [ {
name : "id",
type : "int"
}, {
name : "name",
type : "string"
}],
associations : {
type : "hasMany",
model : "TagItem",
name : "items"
}
});
Adjected TagItem
app.models.TagItem = Ext.regModel("TagItem", {
fields : [ {
name : "id",
type : "int"
}, {
name : "title",
type : "string"
}, {
name : "type",
type : "string"
}, {
name : "tag_id",
type : "int"
}],
associations : {
belongsTo : {
model : "Tag",
name : "items"
}
}
});
TagStore:
app.stores.tagItems = new Ext.data.Store({
model : "app.models.TagItem",
proxy : {
type : 'scripttag',
root : 'items',
url : 'http://www.s-lab.cz/ios/api/tags.php'
}
});
Tags:
app.stores.tags = new Ext.data.Store({
model : "app.models.TagItems",
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
}
});
When I try to load items from the store I get:
Uncaught TypeError: Cannot call method 'read' of undefined
My JSON looks like this:
stcCallback1005([
{
"id":1,
"name":"Doktor",
"url":"doktor",
"items":[
{
"type":"video",
"id":1,
"title":"First tag item",
"tag_id":1
},
{
"type":"article",
"id":1,
"title":"Second tag item - article",
"tag_id":1
},
{
"type":"article",
"id":2,
"title":"Third tag item - article",
"tag_id":1
},
{
"type":"video",
"id":2,
"title":"Fourth tag item",
"tag_id":1
}
]
},
{
"id":2,
"name":"Nemocnice",
"url":"nemocnice"
},
{
"id":3,
"name":"Sestra",
"url":"sestra"
}
]);
Update:
I changed the code with suggestions and the resulting JSON is like this:
stcCallback1005({
"results": [{
"id": 1,
"name": "Doktor",
"url": "doktor",
"items": [{
"type": "video",
"id": 1,
"title": "First tag item",
"tag_id": 1
}, {
"type": "article",
"id": 1,
"title": "Second tag item - article",
"tag_id": 1
}, {
"type": "article",
"id": 2,
"title": "Third tag item - article",
"tag_id": 1
}, {
"type": "video",
"id": 2,
"title": "Fourth tag item",
"tag_id": 1
}]
}, {
"id": 2,
"name": "Nemocnice",
"url": "nemocnice"
}, {
"id": 3,
"name": "Sestra",
"url": "sestra"
}]
});
But still I'm not able to access the subsequent items: app.stores.tags.getAt(0) works, but app.stores.tags.getAt(0).TagItems() does not (neither app.stores.tags.getAt(0).items or app.stores.tags.getAt(0).items() does). And also my template doesn't render correctly: <tpl for=".">{name}<ul><tpl for="items"><li>{title} ({type})</li></tpl></ul></tpl>
Any idea?
I think you don't need to assign a variable for model registration.
Ext.regModel("Tag", {
fields : [ {
name : "id",
type : "int"
}, {
name : "name",
type : "string"
}],
associations : {
type : "hasMany",
model : "TagItem",
name : "items"
}
});
So;
Ext.regModel("TagItem", {
fields : [ {
name : "id",
type : "int"
}, {
name : "title",
type : "string"
}, {
name : "type",
type : "string"
}, {
name : "tag_id",
type : "int"
}],
associations : {
belongsTo : {
model : "Tag",
name : "items"
}
}
});
Add reader to json and correct registered model names.
TagStore:
app.stores.tagItems = new Ext.data.Store({
model : "TagItem", //Use registered name
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
reader: { //add reader to read from json
type: 'json',
root: 'results'
}
}
});
Tags:
app.stores.tags = new Ext.data.Store({
model : "Tag", //Use registered name
proxy : {
type : 'scripttag',
url : 'http://www.s-lab.cz/ios/api/tags.php'
reader: { //add reader to read from json
type: 'json',
root: 'results'
}
}
});
And finally maybe you need to change your json format in tags.php as;
{"results":[
{
"id":1,
"name":"Doktor",
"url":"doktor",
"items":[
{
"type":"video",
"id":1,
"title":"First tag item",
"tag_id":1
},
{
"type":"article",
"id":1,
"title":"Second tag item - article",
"tag_id":1
},
{
"type":"article",
"id":2,
"title":"Third tag item - article",
"tag_id":1
},
{
"type":"video",
"id":2,
"title":"Fourth tag item",
"tag_id":1
}
]
},
{
"id":2,
"name":"Nemocnice",
"url":"nemocnice"
},
{
"id":3,
"name":"Sestra",
"url":"sestra"
}
]
}
I hope it works or helps to correct your code.

Categories