validate Property through object? - javascript

How do I validate the property through object? I have define the list of Property in the checkProperty
I expected missingFields to return Batch.Name is missing.
Currently is is outputting [ 'Batch.Id', 'Batch.Name' ] which is wrong.
let data = {
Batch: {
Id: 123,
},
Total: 100,
}
let checkProperty = ['Total', 'Batch.Id', 'Batch.Name'];
let missingFields = [];
checkProperty.forEach(field => {
if (!data[field]) {
missingFields.push(field);
}
});
console.log(missingFields);

You'll have to use something like reduce after splitting on dots to check whether the nested value exists:
let data = {
Batch: {
Id: 123,
},
Total: 100,
}
let checkProperty = ['Total', 'Batch.Id', 'Batch.Name'];
let missingFields = [];
checkProperty.forEach(field => {
const val = field.split('.').reduce((a, prop) => !a ? null : a[prop], data);
if (!val) {
missingFields.push(field);
}
});
console.log(missingFields);

You can use this
The reason why thisdata[field]when dodata[Batch.Id]it tries to check at the first level key of object. in our case we don't have any key such asBatch.Id.
For our case we need `data[Batch][Id]` something like this which first searches
for `Batch` property and than or the found value it searches for `Id`.
let data = {
Batch: {
Id: 123,
},
Total: 100,
}
let checkProperty = ['Total', 'Batch.Id', 'Batch.Name'];
let missingFields = [];
checkProperty.forEach(field => {
let temp = field.split('.').reduce((o,e)=> {
return o[e] || data[e]
},{});
if (!temp) {
missingFields.push(field);
}
});
console.log(missingFields);

If you can use additional libraries Ajv is perfect for this. Instead of creating all the logic by yourself, you can create a schema and validate it.
var schema = {
"type": "object",
"properties": {
"Batch": {
"type": "object",
"required": ["Id", "Name"],
"properties":
{
"Id":{},
"Name":{},
},
},
"Total": {}
}
};
let json = {
Batch: {
Id: 123,
},
Total: 100,
}
var ajv = new Ajv({
removeAdditional: 'all',
allErrors: true
});
var validate = ajv.compile(schema);
var result = validate(json);
console.log('Result: ', result);
console.log('Errors: ', validate.errors);
Returns the following error message:
dataPath:".Batch"
keyword:"required"
message:"should have required property 'Name'"
params:{missingProperty: "Name"}
schemaPath:"#/properties/Batch/required"
https://jsfiddle.net/95m7z4tw/

Related

JavaScript Array attribute change

I have an array like this.
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
I want to change it to like this
let me explain it a little. I want to assign the abbreviation directly to the name and the iterate through that array
let outout = [
{
"ISB":"ISLAMABAD"
},
{
"RAW":"ISLAMABAD"
},
{
"SWB":"SWABI"
},
{
"AQ":"AQEEL"
},
]
that is what I tried
let k = arr.map((item) => {
return item.ABB = item.name
})
console.log(k)
and here is the output
[ 'ISLAMABAD', 'PINDI', 'SWABI', 'AQEEL' ]
Here you go, use array map, simples
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
let outout = arr.map(({ABBRIVATION, name}) => ({[ABBRIVATION]: name}));
console.log(outout);
Nothing more than a simple Array.prototype.map() needed.
let arr = [
{
ABBRIVATION: "ISB",
name: "ISLAMABAD",
},
{
ABBRIVATION: "RAW",
name: "PINDI",
},
{
ABBRIVATION: "SWB",
name: "SWABI",
},
{
ABBRIVATION: "AQ",
name: "AQEEL",
},
];
const result = arr.map(e => ({ [e.ABBRIVATION]: e.name }));
console.log(result);
map over the array of objects (map returns a new array) and assign the name to a new key defined by the abbreviation.
You code works the way it does because item.ABB is undefined, but you're also assigning item.name to it which does get returned, so you just get an array of names returned.
const arr=[{ABBRIVATION:"ISB",name:"ISLAMABAD"},{ABBRIVATION:"RAW",name:"PINDI"},{ABBRIVATION:"SWB",name:"SWABI"},{ABBRIVATION:"AQ",name:"AQEEL"}];
const out = arr.map(obj => {
return { [obj.ABBRIVATION]: obj.name };
});
console.log(out);
Hi I have seen people answer, but most of them use the map function, I provide some other solutions, hoping to expand the thinking
Use forEach function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
datas.forEach((obj, i, arr) => {
const{'ABBRIVATION':k, 'name':v} = obj;
arr[i] = {[k]:v};
});
console.log(datas);
Use flatMap function
const datas = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
}
];
const result = datas.flatMap(obj => {
const {'ABBRIVATION':k, 'name':v} = obj;
return {[k]:v};
});
console.log(result);
this is how you suppose to do it.
arr.reduce((d, c)=>([...d, {[c.ABBRIVATION]: c.name}]),[])
let arr = [
{
"ABBRIVATION":"ISB",
"name":"ISLAMABAD",
},
{
"ABBRIVATION":"RAW",
"name":"PINDI",
},
{
"ABBRIVATION":"SWB",
"name":"SWABI",
},
{
"ABBRIVATION":"AQ",
"name":"AQEEL",
},
]
console.log(arr.reduce((data, current)=>([...data, {[current.ABBRIVATION]: current.name}]),[]))

How can I merge object values if they have the same key?

I have an Array full of transactions and I want to divide it by day. It will be an array of date that is and array of transations. It may be a little messy but I want to return this structure.
What I tried to do returns me the structure I want, but I don't know how to merge duplicated key values.
This is the array
const transactions = [
{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
This is what I already tried by now
const days = [];
const finalArray = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const datesToMatch = [...new Set(days)].map((date) => {
return { [date]: null };
});
transactions.map((transaction) => {
datesToMatch.map((dayObject) => {
const day = Object.keys(dayObject).toString();
if (day === transaction.day) {
finalArray.push({ [day]: [transaction] });
}
});
});
The output
[ { '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-12T00:00:00.000Z': [ [Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Expected output
[ { '2020-05-12T00:00:00.000Z': [ [Object, Object] ] },
{ '2020-05-02T00:00:00.000Z': [ [Object] ] },
{ '2020-05-08T00:00:00.000Z': [ [Object] ] } ]
Thanks!
Explanation:
dates : extract dates from both fields
uniqueDates : build a Set and convert it into an array so it only has uniqueDates
dateToTransactions : map every unique date to an object with one key (itself) and filter every transaction that is equal to it.
const transactions = [{
name: "Salário",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "1000",
},
{
name: "Pagamento ",
receiveDate: "2020-05-12T00:00:00.000Z",
value: "2350",
},
{
name: "Passagem no VEM",
paidDate: "2020-05-02T00:00:00.000Z",
value: "130",
},
{
name: "Almoço",
paidDate: "2020-05-08T00:00:00.000Z",
value: "50",
},
];
const dates = transactions.map(x => {
const received = x.receiveDate || [];
const paid = x.paidDate || [];
return received + paid;
});
const uniqueDates = [...new Set(dates)];
const dateToTransactions =
uniqueDates.map(
date => {
sameDate = transactions.filter(x => x.receiveDate === date || x.paidDate == date);
return {[date]: sameDate};
});
console.log(dateToTransactions);
I would do something like this:
const days = [];
for (let i = 0; i < transactions.length; i++) {
transactions[i].day = transactions[i].receiveDate || transactions[i].paidDate;
days.push(transactions[i].day);
}
const result = new Map();
days.forEach((day) => {
result.set(day, [])
});
transactions.forEach((transaction) => {
let r = result.get(transaction.day);
r.push(transaction);
result.set(transaction.day, r);
});
Then, in the result map you have a list of the transactions that were made for each day.
This will give the result you expect
const days = {};
const finalArray = transactions.forEach((transaction) => {
let date = (transaction.receiveDate || transaction.paidDate)
if (!days[date]) { days[date] = [transaction]}
else {days[date].push(transaction)}
});
console.log(days);

How to filter array of objects in javascript?

Here is my input :
const data = [
{ group: [{ label: "Can View" }, { label: "Can Create" }] },
{ topgroup: [{ label: "Can View" }, { label: "Can Create" }] },
{ emptyGorup: [] }
];
I am converting array of object to object by using this code
method 1 :
let permissions =
data &&
data.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
a[onlyKey] = b[onlyKey].map(i => i.value);
return a;
}, {});
//Output : {group:["can view","can create"],topgroup:["can view","can create"],emptygroup:[]}
My question is that I don't want to get object property if Object property is empty []. For example, In my output, I can see object property emptygroup is [].
{emptygroup:[]}.
My expected output will be if emptygroup is []
//Output : {group:["can view","can create"],topgroup:["can view","can create"]}
How can I do this ?
Try checking the length of the array
const permissionData = [
{ group: [{ label: "Can View" }, { label: "Can Create" }] },
{ topgroup: [{ label: "Can View" }, { label: "Can Create" }] },
{ emptyGorup: [] }
];
let permissions =
permissionData &&
permissionData.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
if(b[onlyKey].length) {
a[onlyKey] = b[onlyKey].map(i => i.label);
}
return a;
}, {});
console.log(permissions)
You can extend your current code. After you get the object you can filter out the key with empty array using filter and build object again from filtered values
let obj = {
group: ["can view"],
topgroup: ["can view", "can create"],
emptygroup: []
}
let finalObj = Object.fromEntries(Object.entries(obj).filter(([key, value]) => Array.isArray(value) && value.length))
console.log(finalObj)
You can add a condition in reduce:
let permissions =
permissionData &&
permissionData.reduce((a, b) => {
const onlyKey = Object.keys(b)[0];
if (a[onlyKey]) {
a[onlyKey] = b[onlyKey].map(i => i.value);
}
return a;
}, {});

spread operator to copy values to nested object dynamically using array forEach loop

This is the code I made, its actually from the react project I am working on, where I wanted to add more key-value pairs under particular keys. So I made a similar sample code to know how to do it, but unfortunately, I can't find a solution on the internet.
Please help
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter={ [saveName]: { [item.id]: item.value } };
} else
savedFilter={...savedFilter.saveName,...{
...savedFilter.saveName,
...{ [item.id]: item.value }
}};
});
};
savefilter();
console.log("savedFilter :",savedFilter)
output
savedFilter : { das5: 46 }
My Expected output that I wanted
{ fooCriteria: { das: 45, das3: 48, das4: 47, das5: 46 } }
PS: I wanted to give fooCriteria as savename variable there is a reason. since the name of the object is determined by the user
const saveName = document.getElementById("seachSaveInput").value;
const filteredSearchItems=[{"id":"das","value":45},{"id":"das3","value":48},{"id":"das4","value":47},{"id":"das5","value":46}];
let fooCriteria = filteredSearchItems.reduce((acc,{id,value})=>(acc[id]=value,acc),{});
console.log({fooCriteria})
You can use reduce method
instead of forEach reduce makes more sense.
const filteredSearchItems = [
{
'id': 'das',
'value': 45
},
{
'id': 'das3',
'value': 48
},
{
'id': 'das4',
'value': 47
},
{
'id': 'das5',
'value': 46
}
];
const savedFilter = {};
const saveFilter = () => {
const saveName = 'fooCriteria';
savedFilter[saveName] = filteredSearchItems.reduce((saved, item) => {
saved[item.id] = item.value;
return saved;
}, savedFilter[saveName] || {});
};
saveFilter();
console.log('savedFilter :', savedFilter);
I'd do a shallow copy with spread notation:
// If you want to add to the [saveName] entry if it exists:
savedFilter = {...savedFilter, [saveName]: savedFilter ? {...savedFilter[saveName]} : {}};
// If you want to *replace* the [saveName] entry, not add to it:
savedFilter = {...savedFilter, [saveName]: {}};
then update the result with a loop:
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
Here's an example assuming you want to replace the [saveName] property if it exists:
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {...savedFilter, [saveName]: {}};
for (const {id, value} of filteredSearchItems) {
savedFilter[saveName][id] = value;
}
console.log(savedFilter);
There are other, more complicated ways (reduce, map and Object.fromEntries, ...), but they don't have any advantage over the simple, straightfoward loop.
That said, the map and Object.fromEntries version is really concise, if that's your thing:
// Assumes you want to replace the [saveName] property entirely
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
];
let savedFilter = {somethingAlreadyThere: 42};
const saveName = "fooCriteria";
savedFilter = {
...savedFilter,
[saveName]: Object.fromEntries(filteredSearchItems.map(({id, value}) => [id, value]))
};
console.log(savedFilter);
Don't be fooled, though, there's a loop in there (actually two of them, one for map, the other for fromEntries). :-)
Using ...spread operator you can do it something like this:
const filteredSearchItems = [{
"id": "das",
"value": 45
},
{
"id": "das3",
"value": 48
},
{
"id": "das4",
"value": 47
},
{
"id": "das5",
"value": 46
},
]
let savedFilter = "";
const savefilter = () => {
const saveName = "fooCriteria";
let res = {};
filteredSearchItems.forEach(item => {
if (!savedFilter) {
savedFilter = { [saveName]: { [item.id]: item.value } };
} else
savedFilter[saveName] = {
...{ [item.id]: item.value }, ...savedFilter[saveName]
}
});
};
savefilter();
console.log("savedFilter :", savedFilter.fooCriteria)
const filteredSearchItems=[{
"id":"das",
"value":45
},
{
"id":"das3",
"value":48
},
{
"id":"das4",
"value":47
},
{
"id":"das5",
"value":46
},
]
var a1={};
for(let i=0 ; i<filteredSearchItems.length;i++){
let id1 = filteredSearchItems[i].id;
let id2 = filteredSearchItems[i].value;
a1[id1] = id2;
}
var t2 = {"fooCriteria": a1}
console.log(JSON.stringify(t2));
Output : {"njkcnv":{"das":45,"das3":48,"das4":47,"das5":46}}

Remove parent object and child object if value is undefined using Array.filter(?)

Question:
How can I removal all emailAddress that are empty, and if there are no emailAddresses for an approval, remove that approval too.
My current solution will remove approvals when emailAddress completely empty. But not when two emailAddresses are present and one is empty (see script output vs. expected output)
var request = {
approvals: [
{
type: 'media',
emailAddresses: [
{emailAddress: 'frank#gmail.com'},
]
},
{
type: 'other',
emailAddresses: [
{emailAddress: ''},
]
},
{
type: 'scope',
emailAddresses: [
{emailAddress: 'kelly#yahoo.com'},
{emailAddress: ''},
]
}
]
}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
let output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
// EXPECTED OUTPUT:
// approval: [
// {
// type: 'media',
// emailAddresses: [
// {emailAddress: 'frank#gmail.com'},
// ]
// },
// {
// type: 'scope',
// emailAddresses: [
// {emailAddress: 'kelly#yahoo.com'},
// ]
// }
// ]
// }]
Live Code
You are not replacing approval.emailAddresses in your code - you should use:
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
See demo below:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var filterOutEmptyEmails = (approval) => {
approval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
if(approval.emailAddresses.length){
return true;
}
}
var output = request.approvals.filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
EDIT:
Another proposal without mutating the input array - using Array.prototype.reduce to create a new array:
var request={approvals:[{type:'media',emailAddresses:[{emailAddress:'frank#gmail.com'},]},{type:'other',emailAddresses:[{emailAddress:''},]},{type:'scope',emailAddresses:[{emailAddress:'kelly#yahoo.com'},{emailAddress:''},]}]};
var output = request.approvals.reduce(function(p,c){
// creates a shallow copy
var elem = Object.assign({},c);
// replaces the reference to request.approvals by the new array created by the filter
elem.emailAddresses = elem.emailAddresses.filter(x => !!x.emailAddress);
if(elem.emailAddresses.length != 0)
p.push(elem);
return p;
},[]);
// console.log(request.approvals);
console.log(output);
.as-console-wrapper{top:0;max-height:100%!important;}
Possible "non mutation" solution could be like this
var request = {approvals: [{type: 'media',emailAddresses: [{emailAddress: 'frank#gmail.com'},]},{type: 'other',emailAddresses: [{emailAddress: ''},]},{type: 'scope', emailAddresses: [{emailAddress: 'kelly#yahoo.com'},{emailAddress: ''},]}]}
const filterOutEmptyEmails = (approval) => {
if(approval.emailAddresses.filter(x => !!x.emailAddress).length){
return true;
}
}
const output = request.approvals.map(approval => {
const filteredAproval = approval;
filteredAproval.emailAddresses = approval.emailAddresses.filter(x => !!x.emailAddress);
return filteredAproval
}).filter(filterOutEmptyEmails);
console.log(JSON.stringify(output));
console.log(JSON.stringify(request));
Without mutation (with lots of ES6/7 sugar):
const filteredApprovals = request.approvals.reduce((acc, approval) => {
const filteredEmailAddresses = approval.emailAddresses.filter(item => item.emailAddress);
return (filteredEmailAddresses.length > 0) ? [...acc, { ...approval, emailAddresses: filteredEmailAddresses }] : acc;
}, []);
Fiddle: https://jsfiddle.net/free_soul/hndjbce3/

Categories

Resources