json-schema v4 how-to implements enums depending on enums? - javascript

Using json-editor, and looking at this answer, I am trying to do the following, using json-schema v4:
Use a root property to select one of two categories ['clothing', 'accessory'], which will determine enum-values for a material property.
The case I am trying to solve has multiple enum-properties depending on the category-value.
Pseudocode example:
{
"type": "object",
"Title": "Products",
"definitions": {
"clothing": {
"materials": ["yak", "merino"]
},
"accessories": {
"materials": ["brass", "silver"]
}
},
"properties": {
"productType": {
"type": "string",
"enum": [
"clothing",
"accessories"
]
},
"materials": {
"type": "array",
"title": "Materials",
"items": {
"type": "string",
"title": "Material",
"enum": [
{"$ref" : "#definitions/{{productType}}/materials"}
]
}
}
}
}
Any suggestions on how to structure this?

In this case it might be easier to define types for the first level with a oneOf clause, and use enums just in the nested level. Something like:
"definitions" : {
"materialType" : {
"oneOf" : [{
"$ref" : "#definitions/clothing"
}, {
"$ref" : "#definitions/accesories"
}
]
},
"clothing" : {
"materials" : {
"enum" : ["yak", "merino"]
}
},
"accessories" : {
"materials" : ["enum" : ["brass", "silver"]]
}
}
Then you consume materialType like this:
"materials": {"$ref":"#definitions/materialType"}
If you want also to encode the materialType within the object instance, then you may add another property enum like this, but I would not recommend this:
"clothing" : {
"materials" : {
"enum" : ["yak", "merino"]
},
"kind": {"enum" : ["clothing"]}
}

Related

Merge a Product Config JSON with Generic Config JSON- Issue While Merging Arrays inside it

I have 2 different Json files
1: a Deaflut JSON file
2: A Product Based JSON file
I need to merge them together in such a way that if a feature in default is not in a product that needs to be added to product config from default one.
for this merge, I used "lodash.mergewith" https://www.npmjs.com/package/lodash.mergewith.
so this is now taking care of the merge, But the file contains multiple nested JSON arrays inside it.
to handle that there is an option to use a customizer method that can handle array merge as mentioned in the usage of lodash.mergewith. I need a customizer that can find the Label from Deaflut and compare it with the Product if the Product has the same Label value then replace the URL with the Product URL. else if the Label is not in Product config, then use it from default as it is.
Example
Default config.json:-links is an array of this json with path : object►login►options►sections►2►links
"links": [{
"url": "www.google.com",
"label": "Lable1"
},
{
"url": "www.google.com",
"label": "Label2"
},
{
"url": "www.google.com",
"label": "Label3"
},
{
"url": "www.google.com",
"label": "Label4"
}
]
Productconfig.json:- links is an array inside this of the path: object►login►options►sections►2►links
"links": [{
"url": "www.product1.com",
"label": "label1"
},
{
"url": "www.product2.com",
"label": "Label2"
}
]
** after merge mergedconfig.json "Links" need to be like this.**
"links": [{
"url": "www.product1.com",
"label": "Label1"
},
{
"url": "www.product2.com",
"label": "Label2"
},
{
"url": "www.google.com",
"label": "Label3"
},
{
"url": "www.google.com",
"label": "Label4"
}
]
The main concern is this Array is coming inside a JSON file inside some JSON objects
like eg if the Array is inside links[] it will be in a path like : object►login►options►sections►2►links[]. and this Links Array similarly present inside in some other paths eg: object►register►options►sections►2►links[]
So I need to figure out all the Array like this and for each of the Arrays, I need to perform this action.
Just use Array.map and Array.find:
let links= [
{
"url": "www.google.com",
"label": "Label1"
},
{
"url": "www.google.com",
"label": "Label2"
},
{
"url": "www.google.com",
"label": "Label3"
},
{
"url": "www.google.com",
"label": "Label4"
}
];
let plinks= [{
"url": "www.product1.com",
"label": "label1"
},
{
"url": "www.product2.com",
"label": "Label2"
}
];
let results = links.map(lnk=>{
plnk = plinks.find(pl=>pl.label.toLowerCase()===lnk.label.toLowerCase());
return plnk || lnk
});
console.log(results);
for clean access to nested JSON keys you can use ES like this:
let a = {
b: {
c: [1,2,3]
}
};
let {c} = a?.b;
console.log(c);

Nested forEach issue

I have two arrays of object, the first array (printers, around 80 elements) is made of the following type of objects:
[{
printerBrand: 'Mutoh',
printerModel: 'VJ 1204G',
headsBrand: 'Epson',
headType: '',
compatibilty: [
'EDX',
'DT8',
'DT8-Pro',
'ECH',
],
cartridges: [],
},
....
]
The second array (cardridges, around 500 elements) is made of the following type of objects:
[
{
"customData": {
"brand": {
"value": {
"type": "string",
"content": "ECH"
},
"key": "brand"
},
"printer": {
"value": {
"type": "string",
"content": "c4280"
},
"key": "printer"
}
},
"name": "DT8 XLXL",
"image": {
"id": "zLaDHrgbarhFSnXAK",
"url": "https://xxxxxxx.net/images/xxxxxx.jpg"
},
"brandId": "xxxxx",
"companyId": "xxxx",
"createdAt": "2018-03-26T14:39:47.326Z",
"updatedAt": "2018-04-09T14:31:38.169Z",
"points": 60,
"id": "dq2Zezwm4nHr8FhEN"
},
...
]
What I want to do first is to is to iterate through the first array and and then iterate for all the cardridge available: if a the value customData.brand.value of a cardridge is included inside the array 'compatibility' of a printer, then I have to add this cardridge object inside the cardridges array of this printer. I have tried but somehow the iteration doesn't take place correctly. This is what I tried:
printers.forEach((printerItem) => {
const printer = printerItem;
printer.compatibilty.forEach((compatibilityItem) => {
const compatibility = compatibilityItem;
cardridges.forEach((cartridge) => {
if (compatibility === cartridge.customData.brand.value.content) {
printer.cartridges.push(cartridge);
}
});
});
});
What am I doing wrong?
You're accessing the wrong property. It should be cartridge.customData.brandName.value.content, carefully note brandName.value rather than brand.value
Your issue is that you're accessing it by the wrong property - brand and not brandName.
Furthermore, if you're targeting everything but IE, you could simplify your nested for loops to utilize some fancy ES6 array methods.
printers.forEach((p) => {
p.cartridges.push(cartridges.filter((c) => {
const brandName = c.customData.brandName.value.content;
return p.compatibilty.includes(brandName);
}));
});

How to delete a paticular Object in an array inRethinkDB

I am Just trying to learn RethinkDB.I am little Bit Confused That how to delete an single Object in an array,What is the Exact query I have to use if i have to delete this Object
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
}
from whoLikedIt Array
My data
{
"comments": [ ],
"id": "c242c74d-03d9-4963-9a22-4779facb8192" ,
.....
"views": 0 ,
"whoLikedIt": [
{
"name": "Vignesh Warar" ,
"username": "d97bf210-c42d-11e6-b783-07b5fe048705"
},
{
"name": "Ram" ,
"username": "B97bf210-c4d2d-11e6-b783-07b5fev048705"
},
]
.....
}
My Try
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(
{whoLikedIt:r.row('whoLikedIt').filter({username:"B97bf210-c4d2d-11e6-b783-07b5fev048705"}).delete()}
)
Throws Me a error
e: Cannot nest writes or meta ops in stream operations. Use FOR_EACH instead in:
You want:
r.db('image').table('posts').get('c242c74d-03d9-4963-9a22-4779facb8192').update(function(row) {
return {whoLikedIt: row('whoLikedIt').filter(function(obj) {
return obj('username').ne("B97bf210-c4d2d-11e6-b783-07b5fev048705");
})};
})

How to interpret javascript within a json file

I'm working with the form builder Alpaca, and I would like to interpret a javascript function within a json datasource file, to select a certain file :
/data/options.json :
"nature":{
"type": "select",
"dataSource": "function(e) {...}"
},
This file is loaded here :
/test.html :
$("#div").alpaca({
"optionsSource": "/data/options.json",
etc...
Is this possible ?
Thanks.
You can use eval as said :
object = {"nature":{
"type": "select",
"dataSource": "function(e) {alert('ok')}"
}
}
var x = eval("("+object.nature.dataSource+")");
x()
Demo
You could make the function call first, then add the result to you JSON with data.nature.push();
See this answer : Add data to JSON in JS
script type="text/javascript">
var JSON = {"nature":{
"type": "select"
}};
JSON.dataSource.push(function());
$("#form1").alpaca(JSON);
</script>
As the Alpace datasources doc, http://www.alpacajs.org/docs/api/datasources.html you can use custom function in the datasource parameter :
$("#field5").alpaca({
"schema": {
"type": "string",
"title": "Pick an Action Hero"
},
"options": {
"type": "select",
"dataSource": function(callback) {
callback([{
"value": "rambo",
"text": "John Rambo"
}, {
"value": "norris",
"text": "Chuck Norris"
}, {
"value": "arnold",
"text": "Arnold Schwarzenegger"
}]);
}
}
});

How to cast property in nested objects to ObjectId with loopback and mongodb?

Let's say I have the following model definition:
{
"name": "Report",
"idInjection": true,
"trackChanges": true,
"mongodb": {
"collection": "report"
},
"properties": {
"resource" : {"type": "String"},
"date" : {"type": "Date"},
"people" : [ {
// Here's where I like to have an id property.
"role" : {"type": "String"},
"hours" : {"type": "Number"}
} ],
"name" : {"type": "String"}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
Now I want to have id property in each object in people array(to be accessed with like report.people[0].id) and it should be casted to ObjectId on inserts and updates. But well, loopback doesn't have an ObjectId type and the only way seems to be using relations but then how should the foreign key be?
Is there any way to have the id property casted to ObjectId on inserts and updates?
Update:
I tried using embedsMany, but the id wasn't converted:
Here's my report.json:
{
"name": "Report",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"name": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"people" : {
"type": "embedsMany",
"model": "ReportPerson",
"options": {
"validate": true,
"autoId": false
}
}
},
"acls": [],
"methods": []
}
and here's my report-person.json:
{
"name": "ReportPerson",
"base": "Model",
"idInjection": true,
"properties": {
"hours": {"type" : "number"}
},
"validations": [{
"person" : {
"model": "Person",
"type": "belongsTo",
"foreignKey": "id"
}
}],
"relations": {},
"acls": [],
"methods": []
}
When I try to insert this Report using the http API:
{
"name" : "report",
"people" : [
{
"id" : "54c7926e1d621dc65495f069",
"hours" : 2
}
]
}
The id wouldn't be casted to ObjectId and stays as string on the database.
Anyone playing with loopback and mongodb hits this one once in a while.
To get around the lack of ObjectId type in loopback:
-one way is to indeed describe a relation using the property as a foreign key, as discussed in this post
-the other way, much cleaner imo is to define the property as an id in the JSON file
see model definition documentation
for example:
{
"myId": {
"type": "string",
"id": true,
"generated": true
}
}
now a request on this property will work either with pass the actuel objectId or its string representation

Categories