Remove object from a nested object javascript - javascript

I have an object:
s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
I need to remove a nested object from the array of values of ex_obj such that the value of version meets a criteria and store the key of that object it's key in an array.
For example, if I want the object without the child object with a version "2020-04-29t14:14:09" my output would be
{
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
}
]
}
}
Along with an array ['arr1', 'arr2'] as I want the array of keys whose values have been changed.
Here is my attempt. I could remove the object but of course couldn't capture the key.
Object.values(s['ex_obj']).map(e =>e)
.map(x =>
x.filter((f) => {
return f.version != "2020-04-29t14:14:09";
}));
How can I go about getting the output?

x is a local variable containing a reference to the array. Assigning to it doesn't modify the property it came from.
Use Object.entries() so you get both the property name and value, then you can assign back to the property. This will also allow you to make the array of properties that were modified.
s = {
"ex_obj": {
"arr1": [{
"id": "item1",
"version": "2020-04-29t14:14:08"
},
{
"id": "item1",
"version": "2020-04-29t14:14:09"
}
],
"arr2": [{
"id": "item1",
"version": "2020-04-29t14:14:10"
},
{
"id": "item1",
"version": "2020-04-29t14:14:09"
}
]
}
}
let updated = [];
let remove = "2020-04-29t14:14:09";
Object.entries(s.ex_obj).forEach(([key, array]) => {
let filtered = array.filter(({
version
}) => version != remove);
if (filtered.length < array.length) {
s.ex_obj[key] = filtered;
updated.push(key);
}
});
console.log(s);
console.log(updated);

If you are allowed to destroy the original object, you could just loop over the keys and then filter the arrays:
let s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
let ex_obj=s.ex_obj;
for(let key of Object.keys(ex_obj))
ex_obj[key]=ex_obj[key].filter(item=>item.version!=="2020-04-29t14:14:09");
console.log(s);
If you have to make a copy, that's not very different either, just you have to use some kind of cloning, like the JSON-hack, or another:
let s={
"ex_obj":{
"arr1":[
{
"id":"item1",
"version":"2020-04-29t14:14:08"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
],
"arr2":[
{
"id":"item1",
"version":"2020-04-29t14:14:10"
},
{
"id":"item1",
"version":"2020-04-29t14:14:09"
}
]
}
}
let ex_obj=s.ex_obj;
let result={};
for(let key of Object.keys(ex_obj))
result[key]=JSON.parse(JSON.stringify(ex_obj[key].filter(item=>item.version!=="2020-04-29t14:14:09")));
result={ex_obj:result};
console.log(result);

Related

Using Array.map in nested object structure in Java Script

I have below object structure in array
[
{
"modules":set of modules here
"details": [
{
"name":"abc"
"version":"1.2.3"
},
{
"name":"def"
"version":"2.3.4"
},
{
"name":"ghi"
"version":"4.5.6"
}
]
},
{
"modules":set of modules here
"details": [
{
"name":"jkl"
"version":"7.8.9"
},
{
"name":"mno"
"version":"10.11.12"
},
{
"name":"pqr"
"version":"13.14.15"
}
]
}
]
What I want to do is :
get details array transformed into below format for each root object in master array as
"details": [
{
module:"jkl:7.8.9"
},
{
module:"mno:10.11.12"
},
{
module:"pqr:13.14.15"
}
]
So final array would be :
[
{
"modules":set of modules here
"details": [
{
"module":"abc:1.2.3"
},
{
"module":"def:2.3.4"
},
{
"module":"ghi:4.5.6"
}
]
},
{
"modules":set of modules here
"details": [
{
"module":"jkl:7.8.9"
},
{
"module":"mno:10.11.12"
},
{
"module":"pqr:13.14.15"
}
]
}
]
What I have tried and is working is :
rootArray.forEach((entry)=> {
let line = entry.details.map((detailEntry)=>{
//merge detailEntry into single line
})
entry.details = line
});
My question is : is this a right approach or is there any better solution available ?
Two maps is probably the right approach. It will return a new array rather than mutating the original array.
map over the main data array, and then assign the result of mapping over details to the details property of the object that you're returning on each iteration.
const data=[{modules:"set of modules here",details:[{name:"abc",version:"1.2.3"},{name:"def",version:"2.3.4"},{name:"ghi",version:"4.5.6"}]},{modules:"set of modules here",details:[{name:"jkl",version:"7.8.9"},{name:"mno",version:"10.11.12"},{name:"pqr",version:"13.14.15"}]}];
const out = data.map(obj => {
return {
modules: obj.modules,
details: obj.details.map(detail => {
const { name, version } = detail;
return { module: `${name}:${version}` };
})
};
});
console.log(out);
Additional documentation
Destructuring assignment
map
Template/string literals
const data = [
{
"modules": "set of modules here",
"details": [
{
"name":"abc",
"version":"1.2.3"
},
{
"name":"def",
"version":"2.3.4"
},
{
"name":"ghi",
"version":"4.5.6"
}
]
},
{
"modules": "set of modules here",
"details": [
{
"name":"jkl",
"version":"7.8.9"
},
{
"name":"mno",
"version":"10.11.12"
},
{
"name":"pqr",
"version":"13.14.15"
}
]
}
]
const result = data.map( item => ({modules: item.modules, details: item.details.map(i => {
return { module: `${i["name"]}:${i["version"]}` }
})}))
console.log(result)
your approach seems correct.
there is another way to achieve the expected structure, making the copy of the initial array however instead of modifying the existing.
const result = rootArray.map(({ details, ...rest }) => ({
details: details.map(/*transform*/),
...rest
));

frame array of recursive json object from an another array of objects

i have an array of objects of the below format
each with a unique 'sub-task' entry, each of this sub-task is to be embedded as a children element of each unique 'task' from the 'tasks' array
[
{
"sub-task":"abc",
"task":"alpha1"},
{
"sub-task":"def",
"task":"alpha1"},
{
"sub-task":"ijkl",
"task":"proto"},
{
"sub-task":"mno",
"task":"def"},
{
"sub-task":"qrs",
"task":"proto"},
{
"sub-task":"asdf",
"task":"mno"},
]
i was trying to frame an another array of below format
[
{
"name":"alpha1",
"children":[
{
"name":"abc"
},
{
"name":"def",
"children":[
{
"name":"mno"
}
]
}
]
},
{
"name":"proto",
"children":[
{
"name":"ijkl"
},
{
"name":"qrs",
"children":[
{
"name":"asdf"
}
]
}
]
}
]
i was trying of below logic, but ended up with no solution...
var treeData = [];
for( var ele of tasks){
recurOn(treeData,ele);
}
function recurOn(arr,obj){
if(arr.length == 0){
treeData.push({name:obj.parentGroup,children:[{name:obj.groupName}]})
//console.log(treeData);
return 1;
}else {
for(var item of treeData){
if(item.name == obj.parentGroup){
//console.log('item: ', item);
item.children.push({name:obj.groupName});
break;
}
else {
treeData.push(recurOn([],obj))
}
}
return 1;
}
}
//console.log(treeData);
//console.log(result);
Since the no of levels an elements holds is not known i was unable to fix for a logic
Use a map to store object reference.
let input = [
{ "sub-task": "abc", "task": "alpha1" },
{ "sub-task": "def", "task": "alpha1" },
{ "sub-task": "ijkl", "task": "proto" },
{ "sub-task": "mno", "task": "def" },
{ "sub-task": "qrs", "task": "proto" },
{ "sub-task": "asdf", "task": "mno" },
];
let map = new Map, result = [];
input.forEach(({ ["sub-task"]: name, task }) => {
let node = map.get(task), child = { name, children: [] };
if (!node) {
map.set(task, node = { name: task, children: [] });
result.push(node);
}
map.set(name, child);
node.children.push(child);
})
console.log(result);

How to filter array and create new array with specific object keys

I have an array with objects and in each object there is an "items" array. My goal is to combine these "items" into one array.
Goal / Expected Output
[
{ id: 'SUV' },
{ id: 'Compact' },
{ id: 'Gasoline' },
{ id: 'Hybrid' }
]
Sample Array
[
{
"id":"carType",
"items":[
{
"id":"SUV"
},
{
"id":"Compact"
}
]
},
{
"id":"fuelType",
"items":[
{
"id":"Gasoline"
},
{
"id":"Hybrid"
}
]
}
]
You could use Array#flatMap.
const data = [{"id":"carType","items":[{"id":"SUV"},{"id":"Compact"}]},{"id":"fuelType","items":[{"id":"Gasoline"},{"id":"Hybrid"}]}];
const r = data.flatMap(({ items }) => items);
console.log(r);
A one-liner in vanilla JS (earlier than EMCAScript 2019, flatMap is not available, so in case of that...)
[].concat(...arr.map(elt => elt.items))
Something like this?
newArr = []
for (let i = 0;i<arr.length;i++) {
for (let ii = 0;ii<arr[i].items.length;ii++) {
newArr.push(arr[i].items[ii].id)
}
}
console.log(newArr)

How to access field of last element of sub array in an array?

I am having an array (json object converted to array) like
[
{
"_id":{
"$oid":"5ab8d6faff24ae1204000862"
},
"allotment_details":[
{
"allotment_id":"468986c5-2155-01e9-74cb-3ad05c66800d",
"hostel_id":{
"$oid":"5ae69fb4d2ccda0e70005551"
},
"room_id":"ca62d5b5-8fac-62c4-9e62-7e7b9ce9a714",
"food_preference":"Vegetarian",
"from_date":{
"$date":{
"$numberLong":"1527372000000"
}
},
"to_date":{
"$date":{
"$numberLong":"1528063200000"
}
},
"approved_by":{
"$oid":"5af2bda9bc1e370f9c0036d9"
},
"date_of_allotment":{
"$date":{
"$numberLong":"1529487464000"
}
}
},
{
"allotment_id":"c17043a4-7b5b-a132-8226-a4594b61658d",
"hostel_id":{
"$oid":"5ae69fb4d2ccda0e70005551"
},
"room_id":"ca62d5b5-8fac-62c4-9e62-7e7b9ce9a714",
"food_preference":"Vegetarian",
"from_date":{
"$date":{
"$numberLong":"1527372000000"
}
},
"to_date":{
"$date":{
"$numberLong":"1530223200000"
}
},
"approved_by":{
"$oid":"5af2bda9bc1e370f9c0036d9"
},
"date_of_allotment":{
"$date":{
"$numberLong":"1529571140000"
}
}
}
]
}
]
I am trying to tweak the below lines of code
var allotmentDetailsArray = data[0]['allotment_details'];
if (typeof allotmentDetailsArray != 'undefined')
{
if(allotmentDetailsArray.length == 0)
{
isStudentValidForAllotment =true;
}
else
{
//traverse
var to_date_of_last_sub_array= data[0]["allotment_details"][lastIndex]["to_date"];
}
}
I want to get the value of "to_date" in the last element of allotment_details sub array... Please help!!!
To get the last element of an array you can use pop(), or slice(-1).pop() to clone the array before retrieval so the element is not removed. From there you can just access each property by name. Try this:
var data = [{
"allotment_details": [{
"to_date": {
"$date": {
"$numberLong": "1528063200000"
}
}
}, {
"to_date": {
"$date": {
"$numberLong": "1530223200000"
}
}
}]
}]
var date = data[0].allotment_details.slice(-1).pop().to_date.$date.$numberLong;
console.log(date);
Note that I removed the irrelevant properties from the object you provided to make the answer more succinct.
Change the following line
var to_date_of_last_sub_array= data[0]["allotment_details"][lastIndex]["to_date"];
to this:
var to_date_of_last_sub_array= data[0]["allotment_details"][(data[0]["allotment_details"].length - 1)]["to_date"];
MDN Array.length documentation
You can do:
const data = [{"_id":{"$oid":"5ab8d6faff24ae1204000862"},"allotment_details":[{"allotment_id":"468986c5-2155-01e9-74cb-3ad05c66800d","hostel_id":{"$oid":"5ae69fb4d2ccda0e70005551"},"room_id":"ca62d5b5-8fac-62c4-9e62-7e7b9ce9a714","food_preference":"Vegetarian","from_date":{"$date":{"$numberLong":"1527372000000"}},"to_date":{"$date":{"$numberLong":"1528063200000"}},"approved_by":{"$oid":"5af2bda9bc1e370f9c0036d9"},"date_of_allotment":{"$date":{"$numberLong":"1529487464000"}}},{"allotment_id":"c17043a4-7b5b-a132-8226-a4594b61658d","hostel_id":{"$oid":"5ae69fb4d2ccda0e70005551"},"room_id":"ca62d5b5-8fac-62c4-9e62-7e7b9ce9a714","food_preference":"Vegetarian","from_date":{"$date":{"$numberLong":"1527372000000"}},"to_date":{"$date":{"$numberLong":"1530223200000"}},"approved_by":{"$oid":"5af2bda9bc1e370f9c0036d9"},"date_of_allotment":{"$date":{"$numberLong":"1529571140000"}}}]}];
const toDate = data[0].allotment_details[data[0].allotment_details.length - 1].to_date;
console.log(toDate);

Build array from another array if some key are identical using JavaScript

I have an array of data. Some of the key in the array are same. I would like to create a new array based on the key and add the other data.
This is my array
var myObjOne = [
{
"name":"John",
"id":1,
"car":"maruti"
},
{
"name":"John",
"id":2,
"car":"wolks"
},
{
"name":"John",
"id":3,
"car":"bmw"
},
{
"name":"Peter",
"id":4,
"car":"alto"
},
{
"name":"Peter",
"id":5,
"car":"swift"
}
];
I would like to convert the array in to the below format.
var myObj = [
{
"name":"John",
"items": [
{ "id":1, "car":"maruti" },
{ "id":2, "car":"wolks" },
{ "id":3, "car":"bmw" }
]},
{
"name":"Peter",
"items": [
{ "id":4, "car":"alto" },
{ "id":5, "car":"swift" },
]
}
];
I am working on a node environment.
You can create an object using Array#reduce first which maps name with items, and then create the final array by looping over the intermediate map using a for...of loop:
var source = [{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}];
const map = source.reduce((acc, {name, ...obj}) => {
if (!acc[name]) {
acc[name] = [];
}
acc[name].push(obj);
return acc;
}, {});
const result = [];
for (let[name, items] of Object.entries(map)) {
result.push({name, items});
}
console.log(result);
Array.reduce is at rescue.This method accepts an accumulator and current
item. Check in the accumulator if there exist an object where the value of name property is John or Peter
var myObjOne = [{
"name": "John",
"id": 1,
"car": "maruti"
},
{
"name": "John",
"id": 2,
"car": "wolks"
},
{
"name": "John",
"id": 3,
"car": "bmw"
},
{
"name": "Peter",
"id": 4,
"car": "alto"
},
{
"name": "Peter",
"id": 5,
"car": "swift"
}
];
var newObj = myObjOne.reduce(function(acc, curr, currIndex) {
// using findIndex to check if there exist an object
// where the value of the name property is John, Peter
// if it exist it will return the index else it will return -1
let ifNameExist = acc.findIndex(function(item) {
return item.name === curr.name;
})
// if -1 then create a object with name and item property and push
// it to the accumulator
if (ifNameExist === -1) {
let nameObj = {};
nameObj.name = curr.name;
nameObj.items = [];
nameObj.items.push({
id: curr.id,
car: curr.car
})
acc.push(nameObj)
} else {
// if such an object already exist then just update the item array
acc[ifNameExist].items.push({
id: curr.id,
car: curr.car
})
}
return acc;
}, []);
console.log(newObj)
Use .reduce to group by name, and use .find inside the reducer to find if the matching name has already been added:
const input=[{"name":"John","id":1,"car":"maruti"},{"name":"John","id":2,"car":"wolks"},{"name":"John","id":3,"car":"bmw"},{"name":"Peter","id":4,"cars":"alto"},{"name":"Peter","id":5,"cars":"swift"}]
const output = input.reduce((a, { name, ...item }) => {
const foundNameObj = a.find(nameObj => nameObj.name === name);
if (foundNameObj) foundNameObj.items.push(item);
else a.push({ name, items: [item] });
return a;
}, []);
console.log(output);

Categories