Remove objects from nested array using Lodash - javascript

I have the following JSON structure:
{
"id": 123,
"shops": [
{
"shopId": 456,
"products": [
{
"productId": 10001,
"name": "abc",
"state": "active"
},
{
"productId": 10002,
"name": "def",
"state": "expired"
}
]
},
{
"shopId": 789,
"products": [
{
"productId": 20001,
"name": "qrt",
"state": "expired"
},
{
"productId": 20002,
"name": "jbf",
"state": "active"
}
]
}
]
}
I want to remove all products from each shop where the product does not have certain properties.
If I covert it to a flat map then I can do it fine, but then I lose the outer object as I just have an array with all the products that haven't been removed in.
_(shopJson.shops).map('products').flatten().map(x => {if(x.state === 'active'){return x}}).compact().value()
I tried the following but just end up with an empty array:
_(shopJson.shops).map('products').filter(x => x.state === 'active').value()
I also tried using _.reduce() and _.transform() but can't get it to work
The final JSON should look like:
{
"id": 123,
"shops": [
{
"shopId": 456,
"products": [
{
"productId": 10001,
"name": "abc",
"state": "active"
}
]
},
{
"shopId": 789,
"products": [
{
"productId": 20002,
"name": "jbf",
"state": "active"
}
]
}
]
}

You don't really need lodash for this. You can just use Array.prototype.map and Array.protype.filter (and also some spread syntax to shallow merge object properties):
const data = {id:123,shops:[{shopId:456,products:[{productId:10001,name:"abc",state:"active"},{productId:10002,name:"def",state:"expired"}]},{shopId:789,products:[{productId:20001,name:"qrt",state:"expired"},{productId:20002,name:"jbf",state:"active"}]}]};
const result = {
...data,
shops: data.shops.map((shop) => ({
...shop,
products: shop.products.filter((product) => product.state === 'active'),
})),
};
console.log(result);
EDIT: As #Deykun pointed out, if you want to ignore shops that don't have any active products, you can filter shops out using Array.prototype.some in a filter:
const data = {id:123,shops:[{shopId:456,products:[{productId:10001,name:"abc",state:"active"},{productId:10002,name:"def",state:"expired"}]},{shopId:789,products:[{productId:20001,name:"qrt",state:"expired"},{productId:20002,name:"jbf",state:"expired"}]}]};
const result = {
...data,
shops: data.shops
.filter((shop) => shop.products.some((product) => product.state === 'active'))
.map((shop) => ({
...shop,
products: shop.products.filter((product) => product.state === 'active')
}))
};
console.log(result);

Related

How to compare and manipulate json object [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 months ago.
Improve this question
I need to compare and manipulate JSON objects.
First object
let data1 = {
"id": "111",
"entity_id": "222",
"text_id": "333",
"details": [{
"value": 1000,
"comp_id": "444",
"CompName": "driving"
}]
}
Second object
let data2 = [{
"id": "111",
"text_id": "333",
"criteria_type": "TXT",
"value": 1000,
"comp": {
"id": "444",
"name": "driving"
}
}, {
"id": "222",
"text_id": "444",
"criteria_type": "TXT",
"value": 2000,
"comp": {
"id": "555",
"name": "swiming"
}
}]
There are 2 objects data1 and data2. Here, I need to compare the data1.details array with the data2 array key => data1.details.comp_id with data2.comp.id if not match then I need to push value, id and name to data1 object. Please help me to resolve this issue.
Resulting object
data1 will be:
{
"id": "111",
"entity_id": "222",
"text_id": "333",
"declaration_details": [{
"value": 1000,
"comp_id": "444",
"CompName": "driving",
}, {
"value": 2000,
"comp_id": "555",
"CompName": "swiming",
}]
}
Based on your expected result, wouldn't you just need to map data2 to the declaration_details of the resulting object?
const main = () => {
const { details, ...rest } = data1;
const result = {
...rest,
fbp_year: new Date().getUTCFullYear(),
declaration_details: data2.map(({
value,
comp: {
id: comp_id,
name: CompName
}
}) => ({
value,
comp_id,
CompName
}))
};
console.log(result);
};
const
data1 = {
"id": "111",
"entity_id": "222",
"text_id": "333",
"details": [{
"value": 1000,
"comp_id": "444",
"CompName": "driving"
}]
},
data2 = [{
"id": "111",
"text_id": "333",
"criteria_type": "TXT",
"value": 1000,
"comp": {
"id": "444",
"name": "driving"
}
}, {
"id": "222",
"text_id": "444",
"criteria_type": "TXT",
"value": 2000,
"comp": {
"id": "555",
"name": "swiming"
}
}];
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
Use filter() to find objects in the data2 matching comp.id. Then you can just use map() to create a new array. Finally, you can add the mappedData2 array to the data1 in declaration_details.
let filteredData2 = data2.filter(item => {
return data1.details.some(detail => detail.comp_id === item.comp.id);
});
let mapData = filteredData2.map(item => {
return {
value: item.value,
comp_id: item.comp.id,
CompName: item.comp.name
};
});
You can use JSON.stringify(yourJsonObject) to convert your objects to strings.
Then you can compare them like this. areEqual = string1 == string2. Make sure the object properties are in the same order for both objects.

How can i filter result if i have array in body

i have a payload
{
"category": "Mobile",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"1",
"2",
"3"
]
}
i want to find all object which have rating 1 or 2 or 3 and also have any location
Basically i am creating a filter for an ecommerce store i which we will get multiple location and multiple ratings as well so we will return only those object which have matched property. i am attaching a screenshot of UI for better understanding.
i want to run this filter with multiple location and multiple checked checkbox
You can do create a filter dynamically:
const { category, price, location, rating } = req.body;
const filter = {};
if (category) filter.category = category;
if (price) filter.price = { $gte: parseInt(price.from, 10), $lte: parseInt(price.to, 10) };
if (location?.length) filter.location = { $in: location };
if (rating?.length) filter.rating = { $in: rating };
const data = await Collection.find(filter);
If you want to filter your objects, you should use filter() from your array :
const arr = [{
"category": "Mobile1",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"1",
"2",
"3"
]
},
{
"category": "Mobile2",
"price": {
"from": "10",
"to": "50"
},
"location": [
"Jakrta",
"Bandung",
"Surabaya"
],
"rating": [
"2",
"3"
]
}];
const result = arr.filter(el => el.rating.includes("1") || el.rating.includes("2") || el.rating.includes("3"));
console.log(result);

Returning parent key based on a value in a list of arrays in Javascript

{
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
This is list of arrays with keys and values as array, I want to return all the keys based on a particular value;
For Eg:
I want to return the parent keys which are [arr1,arr2], reason being both the arrays contain a value Unique, So I want to return the parent key of both the values, which is arr1 and arr2 respectively.
Note: The list can have n numbers of arrays.
Any help would be appreciated. Thanks in advance.
The simplest way to go about this is:
Loop through the keys in your object
Check if the array contains any objects with the name "Unique"
If so, add the objects key to an array
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
// Create our array that will contain the keys
const keys = []
// Loop through each key in the object
for (const prop in obj) {
// Use .some to see if any of the objects in this array have the selected name
const containsUnique = obj[prop].some(o => o.name === 'Unique')
if (containsUnique) {
// Add the current key to the array
keys.push(prop)
}
}
// Use the array of keys which contain an object named "Unique"
console.log(keys)
This is a more generic approach:
const getKeysByValue = (data, value) => {
const dataKeys = Object.keys(data);
const valueKey = Object.keys(value);
return dataKeys.filter(currKey => {
for(let element of data[currKey])
if(element[valueKey] === value[valueKey])
return true;
});
}
const data = {
"arr1":[
{
"name":"something1",
"shape": "Trapezium",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"shape": "Octagon",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"shape": "Square",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"shape": "Triangle",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"shape": "Circle",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"shape": "Triangle",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
}
],
"arr3":
[
{
"name":"Not-Unique",
"shape": "Circle",
"id":"8hcf14ee58ea25g343e9a2f208df215c"
}
]
}
console.log(getKeysByValue(data, {"name": "something2"})); // ["arr1"]
console.log(getKeysByValue(data, {"name": "Unique"})); // ["arr1", "arr2"]
console.log(getKeysByValue(data, {"shape": "Circle"})); // ["arr1", "arr3"]
console.log(getKeysByValue(data, {"shape": "Square"})); // ["arr1"]
The function receives two parameters, data and value. value is expected to be in the format of the value you are looking to filter with. In your example you wanted it to be "Unique" and in each object in the array it was presented like "name": "Unique" so we will send it as an object, {"name": "Unique"}.
In this way you can have different value to filter with. In the example above I added a shape key and value to each element, we can filter by this value too as shown in the example above.
you can do like this :
const obj = {
"arr1": [{ "name": "something1", "id": "233111f4-9126-490d-a78b-1724009fa484" }, { "name": "something2", "id": "50584c03-ac71-4225-9c6a-d12bcc542951" }, { "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }, { "name": "something4", "id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7" }, { "name": "something5", "id": "ef825dc3-003c-4740-955a-bb437cfb4199" }],
"arr2": [{ "name": "Unique", "id": "43cf14ee58ea4d8da43e9a2f208d215c" }],
"arr3": [{ "name": "No unique here","id": "Example" }]
}
arr=[]
//loop over dict with pair keys and value
for (const [key, value] of Object.entries(obj)) {
//get the list of name from dict and check it if it contains Unique string
value.map(e=>e.name).includes("Unique") ? arr.push(key) : false
}
console.log(arr)
You can use array some method
const data = {
"arr1": [{
"name": "something1",
"id": "233111f4-9126-490d-a78b-1724009fa484"
},
{
"name": "something2",
"id": "50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name": "something4",
"id": "ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name": "something5",
"id": "ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2": [{
"name": "Unique",
"id": "43cf14ee58ea4d8da43e9a2f208d215c"
}]
}
var obj = [],
keys;
for (keys in data) {
data[keys].some(a => "Unique" === a.name) && obj.push(keys);
}
console.log(obj);
An alternative way that i could think of is using Regexp
var obj = {
"arr1":[
{
"name":"something1",
"id":"233111f4-9126-490d-a78b-1724009fa484"
},
{
"name":"something2",
"id":"50584c03-ac71-4225-9c6a-d12bcc542951"
},
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"
},
{
"name":"something4",
"id":"ce0374ba-6d9b-4ff5-98b1-1191d1d2a9a7"
},
{
"name":"something5",
"id":"ef825dc3-003c-4740-955a-bb437cfb4199"
}
],
"arr2":
[
{
"name":"Unique",
"id":"43cf14ee58ea4d8da43e9a2f208d215c"}
]
}
let str = JSON.stringify(obj);
let match = str.matchAll(/\"([\w\d]+)\":\[(?:{[\s\S]+},)*{\"name\":\"Unique\"/g);
let parent = [];
for(let m of match){
parent.push(m[1]);
}

Using JavaScript, how can I filter an array of objects using multiple criteria in a child object

I want to get all the customers who have returned product "2":
// Note that in production this array is much longer
const customers = [
{
"customerId": "1",
"products": [
{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "purchased"
}
]
},
{
"customerId": "2",
"products": [
{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "returned"
}
],
}
]
const returns = customers.filter((customer) =>
customer.products.some((product) => product.productId === "2" && product.status === "returned")
);
console.log(returns);
I thought my use of filter would work - but I am guessing some() doesn't work with multiple criteria? Or am I doing something else wrong? Or is there a better way?
Your condition product.productId === "2" && product.status === "returned" does match only one object
if the productId is '2' AND the status is 'returned' matches the last object which is returned.
if you only want the products that have the Id of '2' then it should be product.productId === "2"
Hope this makes sense
Try using some function for the products.
const customers = [{
"customerId": "1",
"products": [{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "purchased"
}
]
},
{
"customerId": "2",
"products": [{
"productId": "1",
"status": "purchased"
},
{
"productId": "2",
"status": "returned"
}
],
}
]
const returns = customers.filter((customer) =>
customer.products.some((product) => product.productId === "2" && product.status === "returned"))
console.log(returns);

how to turn an object of arrays into array of objects?

the structure of the data axios gets is:
{
"data": {
"project": {
"id": "5ebd525ea3ff2434c0d467f8",
"items": [
{
"name": "item one",
"size": 45,
"createdAt": "2020-05-14T14:15:43.034Z",
},
{
"name": "item two",
"size": 23,
"createdAt": "2020-05-14T14:15:58.508Z",
},
{
"name": "item one",
"size": 93,
"createdAt": "2020-05-14T15:02:19.889Z"
},
{
"name": "item two",
"size": 55,
"createdAt": "2020-05-19T02:48:14.486Z"
}
]
}
}
}
I need to accomplish is two things:
Group the items by name
map to new arrays to render in a chart
the code i have is
async created() {
const response = await axios.get(
`http://localhost:1337/projects/${this.routeId}`
))
const { items } = response.data
//returns new array of only fields needed to send to the chart
const newArray = items.map(({name, size, createdAt}) => ({name, size, createdAt}))
// group items by name **** this creates an object of arrays
const groupBy = (array, key) => {
return array.reduce((result, currentValue) => {
(result[currentValue[key]] = result[currentValue[key]] || [])
.push(currentValue);
return result
}, {})
};
const itemsGroupedByName = groupBy(newArray, 'name')
//this fails *** trying to map an object into a new array
itemsGroupByName.forEach(d => {
const { name, size, createdAt } = d
this.arrItemSize.push({
date: moment(createdAt).format('MMM D YYYY'),
total: size,
name
})
})
},
The code above groups the items as object of arrays -
{ [...], [...], [...], [...] }
The format the chart needs is array of objects
[ {...}, {...}, {...}, {...]
How do I map the grouped items to new arrays?
Thanks for any help
You can use the function Array.prototype.reduce for grouping and the function Object.values for extracting the grouped objects.
This is assuming the property items will contain the grouped objects.
let obj = { "data": { "project": { "id": "5ebd525ea3ff2434c0d467f8", "items": [ { "name": "item one", "size": 45, "createdAt": "2020-05-14T14:15:43.034Z", }, { "name": "item two", "size": 23, "createdAt": "2020-05-14T14:15:58.508Z", }, { "name": "item one", "size": 93, "createdAt": "2020-05-14T15:02:19.889Z" }, { "name": "item two", "size": 55, "createdAt": "2020-05-19T02:48:14.486Z" } ] } } };
let result = Object.values(obj.data.project.items.reduce((a, {name, ...rest}) => {
(a[name] || (a[name] = {items: []}))["items"].push({name, ...rest});
return a;
}, Object.create(null)));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources