简体   繁体   中英

Filtering Complex JSON Data

I would like to filter data by taking the value of serial_number or name as input in the JSON given below. However, I have no idea of figuring out how to look for the data through the entire JSON given the complexity of it. For example, if query.serial_number is 0018, then it should return all the data in that object along with the serial_number.

I had tried a lot of things combining on my own combining the filter and map methods which definitely did not help out. Also, if searching by name, would it be possible to return multiple results if the same name occured more than once in the JSON?

Below is the JSON data:

[
    {
        "district": "Kolkata",
        "ward_no": [
            {
                "ward": "6",
                "grievance": [
                    {
                        "serial_number": "0001",
                        "name" : "Mr.A"
                    },
                    {
                        "serial_number": "0002",
                        "name" : "Mr.B"
                    }
                ],
                "general": [
                    {
                        "serial_number": "0003",
                        "name" : "Mr.C"
                    },
                    {
                        "serial_number": "0004",
                        "name" : "Mr.D"
                    }
                ]
            },
            {
                "ward": "7",
                "grievance": [
                    {
                        "serial_number": "0005",
                        "name" : "Mr.E"
                    },
                    {
                        "serial_number": "0006",
                        "name" : "Mr.F"
                    }
                ],
                "general": [
                    {
                        "serial_number": "0007",
                        "name" : "Mr.G"
                    },
                    {
                        "serial_number": "0008",
                        "name" : "Mr.H"
                    }
                ]
            }
        ]
    },
    {
        "district": "Hooghly",
        "ward_no": [
            {
                "ward": "8",
                "grievance": [
                    {
                        "serial_number": "0009",
                        "name" : "Mr.I"
                    },
                    {
                        "serial_number": "0010",
                        "name" : "Mr.J"
                    }
                ],
                "general": [
                    {
                        "serial_number": "0011",
                        "name" : "Mr.K"
                    },
                    {
                        "serial_number": "0012",
                        "name" : "Mr.L"
                    }
                ]
            },
            {
                "ward": "9",
                "grievance": [
                    {
                        "serial_number": "0013",
                        "name" : "Mr.M"
                    },
                    {
                        "serial_number": "0014",
                        "name" : "Mr.N"
                    }
                ],
                "general": [
                    {
                        "serial_number": "0015",
                        "name" : "Mr.O"
                    },
                    {
                        "serial_number": "0018",
                        "name" : "Bruno Fernandes"
                    }
                ]
            }
        ]
    }
]

I intend to take the inputs this way:

var query = {
   name: "Bruno Fernandes"
};

or when in need of searching by serial_number:

var query = {
   serial_number: "18"
};

Below, I made interfaces for the data, so we can easily see how it is layed out.

Here's a link to a Codesandbox , where you can try the code yourself.

interface Hospital {
  district: string;
  ward_no: Ward[];
}
interface Ward {
  ward: string;
  grievance: Patient[];
  general: Patient[]
}
interface Patient {
  serial_number: string;
  name: string;
}

If we want to get them by serial_number, then we can use three loops for each array.

function getById(id:number){
  for (const hospital of json) {
    for (const ward of hospital.ward_no) {
      for (const patient of ward.general) {
        if (patient.serial_number === id) return patient;
      }
      for (const patient of ward.grievance) {
        if (patient.serial_number === id) return patient;
      }
    }
  }
  return null;
}

We can make it more flexible, if we use keyof so we can choose the property we want to match.

function getPatientBy(prop: keyof Patient, value: string) {
  for (const hospital of json) {
    for (const ward of hospital.ward_no) {
      for (const patient of ward.general) {
        if (patient[prop] === value) return patient;
      }
      for (const patient of ward.grievance) {
        if (patient[prop] === value) return patient;
      }
    }
  }
  return null;
}

This will now give use auto complete on the properties of Patient.

You can then make similar functions for Ward and Hospital.

You need to map them. Will give an example then you can tweak as you need

const data = // YOUR ARRAY
var query = {
   serial_number: "18"
};

{data.filter(item => item.ward_no.grievance.serial_number.includes(query) || item.ward_no.general.serial_number.includes(query)).map((value, index) => {
return(
   <p>{value.ward_no.grievance.serial_number || value.ward_no.general.serial_number}</p>
)}

you can also set this up to search by the name if you need help let me know and I can post a revised answer if this option works for you:)

For javascript, there is an infinity of libraries for manipulating collections and objects, but I recommend

npm i @arcaela/eloquent

I figured after some rigorous browsing through the internet that the Array.flatMap() method is exactly what I was looking for that helped me in resolving this efficiently. The solution is as follows:

var query = {
   serial_number: "0018"
};

dummyData.flatMap(value => value.ward_no.flatMap(
valueArray => ['grievances', 'general', 'urgent', 'services'].flatMap(
value => valueArray[value]))).filter(value => value.serial_number === query.serial_number);

You can read more about the flatMap method from the below link:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap

The above code filters out the object that has a match with the serial_number provided by the user. This can be modified accordingly. The method maps through all the ['grievances', 'general', 'urgent', 'services'] arrays to look for the match. What's basically happening is that the method makes the search in the array deep down to 1 level which is by default. This can be better understood from the Array.flat() method in the link given below.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM