Elegant way to code search within a nested json with arrays inside it in Javascript [closed] - javascript

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 days ago.
Improve this question
Json to be searched:
{ "results":
{ "key1":
[ { "step": "step1", "result": "pass" }
, { "step": "step2", "result": "pending" }
]
}
, "key2":
[ { "step": "step3", "result": "pass" }
, { "step": "step4", "result": "pending" }
]
}
When given a key as Input, It should return for that key,
status=pass if all steps have result=pass.
If any of the result are fail, return fail.
Else if any of the status are pending, return pending.
Is there an elegant yet understandable way to code this ?
Here is my working version.
let subState = "key1";
let validationResultsJson = validationReportJson["results"];
let validationKeys = Object.keys(validationResultsJson);
if (validationKeys.includes(subState)) {
let subStateArr = Object.values(validationResultsJson[subState]);
let result = '';
for (let eachStep of subStateArr) {
result += eachStep.result;
}
if (result.indexOf("fail") > -1) {
console.log("fail");
} else if (result.indexOf("pending") > -1) {
console.log("pending");
} else {
console.log("pass");
}
} else {
console.error("subState doesn't exist");
}
TIA

Assuming all you want is true or false and that as you wrote, it should "pass" (meaning true) when all steps have a result: "pass", you could end up writing something like:
const checkResult = stepEntries => {
return stepEntries.every(x => x.result === "pass")
}
const checkResults = (data) => {
return Object.keys(data).map((key) => checkResult(data[key]))
}
and then call
console.log(checkResults(validationReportJson["results"]))
for this given data:
const validationReportJson = {
"results":
{
"key1": [{ "step": "step1", "result": "pass" }, { "step": "step2", "result": "pending" }],
"key2": [{ "step": "step3", "result": "pass", }, { "step": "step4", "result": "pending" }],
"key3": [{ "step": "step3", "result": "pass", }, { "step": "step4", "result": "pass" }]
}
}
will result in this output
[ false, false, true ]
meaning that the 3rd entry passed, but not the others
Updated from the comments
For key1 passed in, I need the results combined. so that I can return "fail" is any fail present, else if any pending present, return pending else if all pass, return pass
const validationReportJson = {
"results":
{
"key1": [{ "step": "step1", "result": "pass" }, { "step": "step2", "result": "pending" }],
"key2": [{ "step": "step3", "result": "pass", }, { "step": "step4", "result": "pending" }],
"key3": [{ "step": "step5", "result": "pass", }, { "step": "step6", "result": "pass" }],
"key4": [{ "step": "step7", "result": "fail" }, { "step": "step8", "result": "pending" }],
}
}
const checkResult = (key, data) => {
const stepEntries = data[key]
// if there's one "fail", should output "fail"
if (stepEntries.some(x => x.result === "fail")) { return { key, result: "fail" } }
// if there's no "fail", but at least one "pending", should output "pending"
if (stepEntries.some(x => x.result === "pending")) { return { key, result: "pending" } }
// if reached here, it can only have all as "pass"
return { key, result: "pass" }
}
const checkResults = (data) => {
return Object.keys(data).map((key) => checkResult(key, data))
}
console.log(checkResults(validationReportJson["results"]))
output will be
[
{ key: 'key1', result: 'pending' },
{ key: 'key2', result: 'pending' },
{ key: 'key3', result: 'pass' },
{ key: 'key4', result: 'fail' }
]

With some slight modifications, a reducer and filter should do the trick. Any result that is not a pass will result in passed === false.
const data = {
"results": {
"key1":[{"step":"step1","result":"pass"}, {"step":"step2","result":"pass"}],
"key2":[{"step":"step3","result":"pass",},{"step":"step4","result":"pass"}]
}
};
const { results } = data;
const steps = Object.keys(results).reduce((a, k) => [...a, ...results[k]], []);
const passing = steps.filter((o) => o.result === 'pass');
const passed = steps.length === passing.length;
if (passed) {
console.log(`All keys passed`);
} else {
console.log(`${steps.length - passing.length} of the keys did not pass`);
}

Related

Put JSON data inside another object of the same JSON

I need to put the images that are on "included" into "data:{relationships: { field_imagen: { data" but the problem is that i just managed to put only the first image into every index using map and find
noticiasImages.forEach(function(data: { relationships: { field_imagen: {data: {id:any}}}} ) {
var nestedArray = noticiasData.map((noticiasImages: { id: any; }) => noticiasImages == noticiasData);
data = nestedArray && noticiasImages || noticiasData;
});
And this is my json (example node)
{
"data": [
"relationships": {
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
}
],
}
]
},
this is the included object, who is in the same level as data
"included": [
"attributes": {
"drupal_internal__fid": 8798,
"langcode": "es",
"filename": "_DSC6472 - copia.jpg",
"uri": {
"value": "public:\/\/2019-11\/_DSC6472 - copia.jpg",
"url": "\/sites\/default\/files\/2019-11\/_DSC6472%20-%20copia.jpg"
},
},
,
Expected Result:
"data": [
"relationships": {
"type": "node--actualidad_institucional",
"id": "71514647-af49-4136-8a28-9563d133070a",
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
"uri": {
"value": "public:\/\/2019-11\/_DSC6472 - copia.jpg",
"url": "\/sites\/default\/files\/2019-11\/_DSC6472%20-%20copia.jpg"
},
}
}
},
I put the uri from included into field_imagen. Tried to resolve like that, but it just put only the first image of the Array from the included object in every node:
showNoticias() {
this.frontService.getNoticias()
.subscribe((data: Noticias) => {
this.noticiasImages = Array.from(data.included);
this.noticiasData = Array.from(data.data);
let noticiasImages = this.noticiasImages.map((data: {id: any}) => data.id);
let noticiasData = this.noticiasData.map((data:{relationships: { field_imagen: { data: { id: any; }}}}) => data.relationships.field_imagen.data.id);
noticiasImages.forEach(function(data: { relationships: { field_imagen: {data: {id:any}}}} ) {
var nestedArray = noticiasData.map((noticiasImages: { id: any; }) => noticiasImages == noticiasData);
data = nestedArray && noticiasImages || noticiasData;
});
console.log(data);
});
}
Hope you can help me, thanks!
UPDATE: tried that but didnt work like expected
let merged = data.data.map((data:{relationships: { field_imagen: { data: any }}}) => Object.assign({}, noticiasImages));
console.log(data)
console.log(merged)
Sometimes using regular for loops are a better option. Using map with objects that have that many properties can get confusing. And using forEach will not give you access to the i index of the iteration in the loop, which makes things easier in this case.
for (let i = 0; i < obj.included.length; i++) {
let uri = obj.included[i].attributes.uri;
obj.data[i].relationships.field_imagen.data[0] = {
...obj.data[i].relationships.field_imagen.data[0],
...uri
}
}
console.log(obj)
Output:
{
"data": [
{
"relationships": {
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
"value": "public://2019-11/_DSC6472 - copia.jpg",
"url": "/sites/default/files/2019-11/_DSC6472%20-%20copia.jpg"
}
]
}
}
}
],
"included": [
{
"attributes": {
"drupal_internal__fid": 8798,
"langcode": "es",
"filename": "_DSC6472 - copia.jpg",
"uri": {
"value": "public://2019-11/_DSC6472 - copia.jpg",
"url": "/sites/default/files/2019-11/_DSC6472%20-%20copia.jpg"
}
}
}
]
}

Partial selection on Inner Join

I need select ony on field to services, look:
async find(): Promise<AccountEntity[]> {
const result = await this.repository
.createQueryBuilder("account")
.select(['account', 'accountServices', 'service.description'])
.leftJoinAndSelect("account.accountAndServices", "accountServices")
.leftJoinAndSelect("accountServices.service", "service")
.getMany();
return result === undefined ? null : result;
}
How to ? please.
I don't want null attributes to appear and I also want to choose which attributes to show
I need :
{
"message": "",
"success": true,
"data": [
{
"id": 1,
"name": "STONES TECNOLOGIA LTDA",
"accountAndServices": [
{
"service": {
"name": "Construção de uma casa",
},
"date_initial": "2021-08-01T07:39:18.000Z",
"date_final": "2021-08-01T07:39:20.000Z",
"value": "10.00",
"created_by": 1,
"is_active": true,
"id": 1,
"pay_day": 10,
"nfse": 0,
"created_at": "2021-08-01T07:39:27.000Z",
},
{
"service": {
"name": "Desenvolvimento de sistemas",
},
"date_initial": "2021-08-01T07:40:01.000Z",
"date_final": "2021-08-01T07:40:02.000Z",
"value": "20.00",
"created_by": 1,
"is_active": true,
"id": 2,
"pay_day": 20,
"nfse": 0,
"created_at": "2021-08-01T07:40:11.000Z",
}
]
}
],
"errors": null
}
I Need selection only field on entity join.
Select with innerJoin you must use addSelect(...).
The find function must not manipulate any data and should return an array of AccountEntity (empty if not found):
function find(): Promise<AccountEntity[]> {
return this.repository
.createQueryBuilder("a")
.innerJoin("account.accountAndServices", "as")
.innerJoin("accountServices.service", "s")
.select(['a.id', 'a.name', 'a.status'])
.addSelect(['as.date_initial', 'as.date_final', 'as.service_id', 'as.value', 'as.nfse', 'as.value', 'as.created_by', 'is_active', 'pay_day', 'created_at'])
.addSelect(['s.name'])
.getMany();
}
Note that to obtain the result from the function you must use await.
Moreover, surround it with try and catch for a better error handling.
Example:
try {
const accounts: AccountEntity[] = await find();
} catch(error) {
console.error(`Error: ${error}`);
}
To transform the array of AccountEntity to another object:
function transform(accounts?: AccountEntity[]) {
return {
message: "",
success: accounts !== undefined,
data: accounts,
errors: null
};
}

How to check if array is empty or not and return value inside foreach in angular8

I have below data,
What i want to do is, i need to check values[] array in each object,
if it is empty then return true, else if values[] array has some record, it will return false.
i have created function for this, but it is reuturning false everytime.
if it is true thn i want to hide table. Table are multiple not single one, so if values arrayis empty thn only want to hide particular table.
{
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
}
Code
hideContextTable(rows) {
const data = rows;
if (data.records) {
data.records.forEach(function (record) {
if (record.values.length === 0) {
return true;
}
});
}
return false;
}
deleteAllContextData(data) {
const tbl = this.hideContextTable(data);
console.log(tbl,"tbl");
if (tbl) {
this.showContextTables = false;
}
}
Simply check the length of returned data from filter function.
data = {
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
};
function hideContextTable(data) {
const result = data.records.filter(record => record.values.length);
const flag = result.length ? true : false;
console.log(flag)
}
hideContextTable(data);
return in the higher order function of forEach will not cause flow to leave the hideContextTable function. You should use a variable that is accessible from outside that function and set it if the condition is met, then return that variable at the end of the function.
const rows = {
"records": [
{
"context": {
"team": [
"MYTEAM-Consume-TEAM-SETUP-ADMIN"
]
},
"values": []
},
{
"context": {
"team": [
"TEAM1"
]
},
"values": [
{
"value": "red",
"label": "dd"
}
]
},
{
"context": {
"team": [
"Test"
]
},
"values": []
},
]
}
function hideContextTable(rows) {
let isEmpty = false;
const data = rows;
if (data.records && data.records.values) {
data.records.forEach(function (record) {
if (record.values.length === 0) {
isEmpty = true;
return; // this is a higher order function
// meaning: it won't leave the context of hideContextTable
}
});
}
return isEmpty;
}
const test = hideContextTable(rows);
console.log(test);

alter array of object value base on dynamic property

I have array of object like this
let arr = [
{
"james-0": {
"value": "",
"error": false
},
"john-0": {
"value": "",
"error": false
},
"jordan-0": {
"value": "",
"error": false
}
}
]
I want to alter error to true if the value is not false / empty string.
I tried this but it deosn't seem to work, I can't hardcode james-${i}
arr = arr.map((o,i) => {
let prop = o[`james-${i}`]
if(!prop.value) prop.error = true
console.log(prop)
return {
...o,
[`james-${i}`]: prop
}
})
simply that ?
let arr =
[ { "james-0": { "value": "", "error": false }
, "john-0": { "value": "abc", "error": false }
, "jordan-0": { "value": "", "error": false }
}
]
Object.keys(arr[0]).forEach( e=> arr[0][e].error = ( arr[0][e].value == ''))
console.log( arr )
You can try this approach
let arr = [
{
"james-0": {
"value": "",
"error": false
},
"john-1": {
"value": "",
"error": false
},
"jordan-2": {
"value": "val",
"error": false
}
}
];
arr = arr.map(value => {
Object.keys(value).forEach(key => {
if (!value[key].value) {
value[key].error = true;
}
})
return value;
})
console.log(arr);
.

Check all the lines

I am a bit stuck, I need a way to make sure all the lines contain "new" in the status or otherwise return false,
var found = data.Lines.find(function(line) {
if (line.status.some(({
status
}) => status !== "new")) {
return false;
}
});
See example http://jsfiddle.net/sucL9rnm/10/
Data
var data = {
"id": 1,
"Lines": [{
"id": 111,
"status": [{
"status": "new"
}]
},
{
"id": 111,
"status": [{
"status": "new"
}]
},
{
"id": 111,
"status": [{
"status": "new"
}]
}
]
}
I gotchu man. Here's a simple solution with a for-loop:
function isFound() {
for (var i = 0; i < data.Lines.length; i++)
if (data.Lines[i].status[0].status !== 'new')
return false;
return true;
}
JSFiddle: http://jsfiddle.net/sucL9rnm/24
This function will return true only if all nested elements of data.lines have the "new" status attribute. Give it a try. Let me know if you have any additional questions.
Here is a possible solution :
var data = {
"id": 1,
"Lines": [{
"id": 111,
"status": [{
"status": "new"
}]
},
{
"id": 111,
"status": [{
"status": "new"
}]
},
{
"id": 111,
"status": [{
"status": "new"
}]
}
]
}
console.log(data.Lines.every(d => d.status[0].status === 'new'));
Using .map and .filter:
data.Lines.filter(line => {
return line.status && line.status.map(item => item.status)
.filter(status => status == 'new')
.length == 0
})
.length > 0
This solution takes into account that data.Lines may have a status with more than one object in it.
Just an approach using short IF and filter
(data.Lines.filter(o=>{
return o.status[0].status !='new';
}).length)?console.log(false):console.log(true)
With status length more than 0:
(data.Lines.filter(o=>{
return o.status.filter(o2=>{
return o2.status !='new';
}).length
}).length)?console.log(false):console.log(true)
Here a non-standard approach, the advantage, is not necessary to know exactly how the object is.
(data.Lines.length == JSON.stringify(data).match(/new/g).length)?console.log(true):console.log(false);

Categories