How to search an array of objects using another array of objects - javascript

I have an array of objects like this
[
{
"prop1": "value1",
"prop2": "value1",
"check": {
"gender": ['male'],
"office": ['London','New York']
}
},
{
"prop1": "value2",
"prop2": "value2",
"check": {
"gender": ['female'],
"office": ['Berlin', 'New York']
}
}
]
I want to search this array passing another object, that will be compared to the check property of the array. So, if I search using this object
{
"office": ['New York']
}
I will get back both elements of the above array, but if I search using this one
{
"gender": ['male'],
"office": ['London']
}
this will return the first element only. I want also to be able to pass something like
{
"gender": ['female'],
"office": ['London', 'Berlin'] // <- 2 elements here
}
and get back the second element. I can check if the objects are the same but I don't know how to do a partial search, how can I do that?

filter() the data
Check if every() key has some() value including (includes()) in the data check array
const data = [{"prop1": "value1", "prop2": "value1", "check": {"gender": ['male'], "office": ['London','New York'] } }, {"prop1": "value2", "prop2": "value2", "check": {"gender": ['female'], "office": ['Berlin', 'New York'] } } ];
const filters = {
"office": ['Berlin']
}
const customFilter = (data, filters) => {
const fKeys = Object.keys(filters);
return data.filter(o =>
fKeys.every(k => (
filters[k].some(fVal =>
o.check[k].includes(fVal)
)
))
);
};
// Without indentations
// return data.filter(o => fKeys.every(k => filters[k].some(fVal => o.check[k].includes(fVal))));
const result = customFilter(data, filters);
console.log(result);

const searchIn = (data, search) => data.filter(value => {
const arr = Object.entries(search).filter(([key, data]) => {
return value.check[key].some(a => data.includes(a))
})
return arr.length
})

Related

Need to filter an JavaScript object

I need to filter an JS object as below format. I have some array of Object. every object contain title and data. I need to filter the object. title will not repet in object it will make an array of data and store every data in that.
Object
let results = [
{
"title": "exam",
"data": {
"status": "Active",
"studentId": "44",
"universityId": "0",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
}
},
{
"title": "prospectus",
"data": {
"status": "Active",
"studentId": "44",
"universityId": "0",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
}
},
{
"title": "prospectus",
"data": {
"status": "Active",
"studentId": "44",
"universityId": "23",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
}
},]
Filter object will be like this. title will not be repeated it will make an array.
"results": [
{
"title": "exam",
"data": {
"status": "Active",
"studentId": "44",
"universityId": "0",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
}
},
{
"title": "prospectus",
"data": [{
"status": "Active",
"studentId": "44",
"universityId": "0",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
},
{
"status": "Active",
"studentId": "44",
"universityId": "23",
"mediaId": "12",
"mediaName": "massey university",
"mediaSrc": "https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg",
"mediaDownload": 4
}]
I have tried this.
let filterData = [];
mainData.data.results.map((value) => {
if (filterData.length == 0) {
let obj = {
title: "title",
data: [{ ...value.data }],
};
filterData.push(obj);
} else {
let found = false;
}
});
This isn't really a filter operation, more of a reduce job where you want to collect data for the same title.
For that, I'd recommend creating a map of title to data
// this is just your data structure minified
const results = [{"title":"exam","data":{"status":"Active","studentId":"44","universityId":"0","mediaId":"12","mediaName":"massey university","mediaSrc":"https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg","mediaDownload":4}},{"title":"prospectus","data":{"status":"Active","studentId":"44","universityId":"0","mediaId":"12","mediaName":"massey university","mediaSrc":"https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg","mediaDownload":4}},{"title":"prospectus","data":{"status":"Active","studentId":"44","universityId":"23","mediaId":"12","mediaName":"massey university","mediaSrc":"https://unisearch-static-contents.s3.ap-southeast-1.amazonaws.com/ADMIN/massey%20university-9a2b9a22-b648-4ef1-a806-97bb0da9b337.jpg","mediaDownload":4}}];
// Collect data by title
const collect = results.reduce(
(map, { title, data }) => ({
...map,
[title]: [...(map[title] ?? []), data],
}),
{}
);
// Convert the mapped object to an array of objects
// with `title` and `data` properties
const filterData = Object.entries(collect).map(([title, data]) => ({
title,
data,
}));
console.log(filterData);
.as-console-wrapper { max-height: 100% !important; }
This will always put data in an array which keeps your data-structure consistent. If you really want single-element arrays to be destructured, use this instead for the last part
const filterData = Object.entries(collect).map(([title, data]) => ({
title,
data: data.length === 1 ? data[0] : data,
}));
The main problem here is to remember which title already exists and reduce it to just one with the data of all the same titles.
The above solution is good but it has a complexity of O(n^2) because it performs two loops. One to reduce the elements into an array of { title: [datas]} objects and one to transform it into the desired output of the form [{title, datas},...].
Using this solution we can perform the process with a complexity of O(n), using a hash table (directory) structure to remember the titles and reduce only those that are repeated.
let filterData = []
let directory = {}
mainData.data.results.map( (obj) => {
if(directory[obj.title] === undefined) {
directory[obj.title] = filterData.length
filterData.push({title: obj.title, data: [obj.data] })
} else {
filterData[directory[obj.title]].data.push(obj.data)
}
})
var resultObj = {}
results.forEach((item)=>{
if(!resultObj[item.title]){
resultObj[item.title] = {
title:item.title,
data:[]
}
}
resultObj[item.title].data.push(item.data)
})
var finalResultList = Object.values(resultObj)
console.log(finalResultList)

How do I set value of nested object to key of current object?

This array has the key to substitute with nested key of 'name'
const arr = ['status', 'user', ...] <-- This array contains key to be replaced with name
This is what my current response object is
[
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}
]
How do I modify the above array of objects to this below
[
{
"id": 11,
"location": "Mumbai",
"status": "NEW",
"user": "Rakesh"
}
]
can try below code
const keys = ['status', 'user']
let arr = [
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}
]
arr.map(a => keys.forEach(k => {
if(a[k] && a[k].name) a[k] = a[k].name
}));
console.log(arr);
I'd try this one:
const results = [
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}, {
"id": 12,
"location": "Helsinki",
"status": {
"name": "NEW"
},
"user": {
"name": "Samuli"
}
}
];
const flattenObject = ([key, value]) => ((typeof value === 'object') ? {[key] : value[Object.keys(value)[0]]} : {[key]: value});
const reduceToSingleObject = (acc, b) => ({...acc, ...b});
const actualResults = results.map((result) => Object.entries(result).map(flattenObject).reduce(reduceToSingleObject));
console.log(actualResults);
Explanation:
flattenObject is a function to flatten structure of object inside object. This only takes the first prop (without knowing the name of the key). If you, for some reason, would need to flatten several key-values, then it'd need whole different kind of helper function to sort that out.
reduceToSingleObject is a function to put all the key-value pairs into a single object. This could have been done already in flattenObject function, but for the clarity, I separated it to a normal map - reduce pattern.
actualResults is the outcome where we go through all the entries of your original results.

Iterate Nested Value in Array in JavaScript/ES6/ES7

I need to iterate a nested value in my javascript.
My wanted output should be like this
shows: ['food.order', 'drink.order', 'play.basketball', 'play.soccer']
const results = [
{
"ID": "shops",
"Shopping": [
{
"ID": "food.order",
"Name": "Food"
},
{
"ID": "drink.order",
"Name": "Drink"
}
]
},
{
"ID": "fun",
"Sports": [
{
"ID": "play.basketball",
"Name": "Basketball"
},
{
"ID": "play.soccer",
"Name": "Soccer"
},
]
}
];
console.log(results);
const final = { shows: results.map(data => data['key'].ID) }
Your question is not clear though, but I am assuming that you are searching for ID property and want to grab the value of the ID and make an array. You can try this way-
const results = [{"ID": "shops", "Shopping": [{ "ID": "food.order", "Name": "Food"},{ "ID": "drink.order", "Name": "Drink"}]},{"ID": "fun", "Sports": [{ "ID": "play.basketball", "Name": "Basketball"},{ "ID": "play.soccer", "Name": "Soccer"}]}];
const ans = results.reduce((acc, item) => {
// Iterate throw the each item's properties
Object.values(item).forEach(val => {
// Filter out the objects which has the `ID` property and get the value of the `ID`.
const ids = typeof val === 'object' && val instanceof Array
? val.filter(x => x.ID !== undefined).map(({ID}) => ID)
: [];
acc = [...acc, ...ids];
});
return acc;
}, []);
console.log(ans);
.as-console-wrapper {min-height: 100%!important; top: 0}
Are you looking for something like this?
const results = [{"ID": "shops", "Shopping": [{ "ID": "food.order", "Name": "Food"},{ "ID": "drink.order", "Name": "Drink"}]},{"ID": "fun", "Sports": [{ "ID": "play.basketball", "Name": "Basketball"},{ "ID": "play.soccer", "Name": "Soccer"}]}];
const final = results.reduce((p, n) => {
// Get all object's array props and then reduce their keys
const mapped = Object.keys(n).filter((key) => Array.isArray(n[key])).reduce((arr, key) => [
...arr,
// Get the array by using the object's key, filter out all objects which don't have
// an 'ID' key, and return a new array which only contains the x.ID property
...n[key].filter((x) => x.ID).map((x) => x.ID)
], []);
return [
...p,
...mapped,
];
}, []);
console.log('final', final);
const results=[{ID:"shops",Shopping:[{ID:"food.order",Name:"Food"},{ID:"drink.order",Name:"Drink"}]},{ID:"fun",Sports:[{ID:"play.basketball",Name:"Basketball"},{ID:"play.soccer",Name:"Soccer"}]}];
let arr = results.flatMap(e => Object.values(e).filter(n => Array.isArray(n))) // at this stage you have an array of arrays
.flat() // at this stage you have flat array from previous stage
.map(s => s.ID) // Now you pick the IDs
console.log(arr)

Extract only required variable from Response - Angular 7

I have the following interface
interface Employee{name?:string;id?:string;role?:string;}
I Have a Response like this
{
"name": "John",
"id": "ID77777",
"role": "Engineer",
"bloodType": "O+ve",
"placeOfDeployment": "NY"
}
I want to extract only the member variables of Interface.So after i am done with the mapping i should get
{
"name": "John",
"id": "ID77777",
"role": "Engineer"
}
You can use lodash which has pick function or here's vanilla js with same result.
const res = {"name": "John","id": "ID77777","role": "Engineer","bloodType": "O+ve","placeOfDeployment": "NY"};
const user = ["name", "id", "role"].reduce((acc, key) => {
acc[key] = res[key];
return acc;
}, {})
Note: handle case where res has missing keys.
You can use object destructing
const response = {
"name": "John",
"id": "ID77777",
"role": "Engineer",
"bloodType": "O+ve",
"placeOfDeployment": "NY"
}
// this will extract name,id,role property from response
const {name,id,role} = response;
// create a new object and assign those properties
let obj = {
name,
id,
role
};
console.log(obj)
You can use ts-transformer-keys, which enables you to obtain keys of given type.
import { keys } from 'ts-transformer-keys';
const keysOfEmployee = keys<Employee>();
const response = {
"name": "John",
"id": "ID77777",
"role": "Engineer",
"bloodType": "O+ve",
"placeOfDeployment": "NY"
};
const result = {};
keysOfEmployee.forEach(k => result[k] = response[k]);

API response is array of arrays. The first array being the key in key-value pair of an object

Here's what my process would be. I would take the first array, assign the values as object keys to my template. I would then want use that template, assign the next array's elements as values to it, and then push that to the final response object. I would then continue to do that until I've reached the end of the response array. I essentially want to convert this to JSON, using the first response array's elements as values for all.
Here's the response:
[
[
"POP",
"GEONAME",
"state"
],
[
"4863300",
"Alabama",
"01"
],
[
"741894",
"Alaska",
"02"
],
[
"6931071",
"Arizona",
"04"
],
[
"2988248",
"Arkansas",
"05"
],
[
"39250017",
"California",
"06"
]
]
Here's the output I want (The keys are always are the first response index)
{
{
"POP": "4863300"
"GEONAME": "Alabama"
"state": "01"
}
{
"POP": "741894"
"GEONAME": "Alaska"
"state": "02"
},
{
"POP": "6931071"
"GEONAME": "Arizona"
"state": "04"
},
{
"POP": "2988248"
"GEONAME": "Arkansas"
"state": "05"
},
{
"POP": "39250017"
"GEONAME": "California"
"state": "06"
}
}
Here's what I have so far:
function modifyArrayResponse(response) {
// Create template (Assign keys)
let template = {};
let keys = response[0];
// Assign keys to template
for(let i = 0; i < keys.length; i++){
template[keys[i]] = template[i];
}
// Use the template (Assign values)
// Return modified response
}
Your desired output is not valid. You have {} around the whole thing, but that's for objects, which need to be key: value pairs. What you should desire is an array of objects:
[
{
"POP": "4863300"
"GEONAME": "Alabama"
"state": "01"
}
{
"POP": "741894"
"GEONAME": "Alaska"
"state": "02"
},
{
"POP": "6931071"
"GEONAME": "Arizona"
"state": "04"
},
{
"POP": "2988248"
"GEONAME": "Arkansas"
"state": "05"
},
{
"POP": "39250017"
"GEONAME": "California"
"state": "06"
}
]
The code to create this needs to loop over all the elements after the first.
function modifyArrayResponse(response) {
const keys = response[0];
const result = [];
for (let i = 1; i < response.length; i++) {
const obj = {};
keys.forEach((key, index) => obj[key] = response[i][index]);
result.push(obj);
}
return result;
}
var input = [
["POP", "GEONAME", "state"],
["4863300", "Alabama", "01"],
["741894", "Alaska", "02"],
["6931071", "Arizona", "04"],
["2988248", "Arkansas", "05"],
["39250017", "California", "06"]
];
console.log(modifyArrayResponse(input));
maybe like this
var oData = [
[
"POP",
"GEONAME",
"state"
],
[
"4863300",
"Alabama",
"01"
],
[
"741894",
"Alaska",
"02"
],
[
"6931071",
"Arizona",
"04"
],
[
"2988248",
"Arkansas",
"05"
],
[
"39250017",
"California",
"06"
]
];
var oResult = [];
var columns = null;
oData.forEach(function(data) {
if (columns === null) {
columns = data;
} else {
var oEntry = {};
oResult.push(oEntry);
data.forEach(function(d, i) {
oEntry[columns[i]] = d;
});
}
});
console.log(oResult);
Using shift() to get and remove column names and then map() remainder of array and use reduce() on columns to create each object
let cols = data.shift()
let res = data.map(arr => cols.reduce((a, c, i) => (a[c] = arr[i], a), {}))
console.log(res)
<script>
var data = [
["POP", "GEONAME", "state"],
["4863300", "Alabama", "01"],
["741894", "Alaska", "02"],
["6931071", "Arizona", "04"],
["2988248", "Arkansas", "05"],
["39250017", "California", "06"]
]
</script>
You can separate the keys and values into separate arrays, and then iterate over the values with Array.prototype.map and construct the objects with Array.prototype.reduce:
const data=[["POP","GEONAME","state"],["4863300","Alabama","01"],["741894","Alaska","02"],["6931071","Arizona","04"],["2988248","Arkansas","05"],["39250017","California","06"]];
const [keys, ...vals] = data;
const result = vals.map(item => item.reduce((all,v,i) => (all[keys[i]] = item[i], all), {}));
console.log(result);

Categories