Ramda get keys from nested object inside array - javascript

I have an array of nested objects. I am trying to iterate though the array and get back a list of ids from the nested objects.
"group": [
{
"groupId": "1",
"subGroup": {
"id": "44",
"name": "Testing",
}
},
{
"groupId": "2",
"subGroup": {
"id": "45",
"name": "Testing",
}
},
{
"groupId": "3",
"subGroup": {
"id": "46",
"name": "Testing",
}
}
]
I am trying to return a list of ids like so => [44, 45, 46]
I tried const result = map(path("subGroup", "id"), group), but it did not produce the result I need.

The approach you've taken is fine, except that R.path expects an array of path indexes rather than multiple arguments.
map(path(["subGroup", "id"]), group)
Alternatively, you could also just use the map method of arrays to achieve the same result.
group.map(g => g.subGroup.id)

Related

Remove the first bracket from nested array

I have an array as follow:
let data =[
[
{
"Id": "110d611c-54e4-4593-a835-def0f34ed882",
"duration": 30,
"name": "burger",
"price": 10,
}
],
[
{
"Id": "edc241e9-5caf-4f0b-b6ea-6cf5fc57d260",
"duration": 10,
"name": "Cake",
"price": 5,
}
]
]
I am trying to remove the first bracket to be like this:
let data =
[
{
"Id": "110d611c-54e4-4593-a835-def0f34ed882",
"duration": 30,
"name": "burger",
"price": 10,
}
],
[
{
"Id": "edc241e9-5caf-4f0b-b6ea-6cf5fc57d260",
"duration": 10,
"name": "Cake",
"price": 5,
}
]
I have trying many solutions, the most common one i have tried is using this way:
let newData = data[0]
but the result always giving me the first nested array something like this:
[
{
"Id": "110d611c-54e4-4593-a835-def0f34ed882",
"duration": 30,
"name": "burger",
"price": 10
}
]
I tried to convert it to string using JSON.stringify() then remove the bracket by doing
JSON.stringify(data).substring(1, JSON.stringify(data).length - 1);
But then when i parse it i get this error:
SyntaxError: JSON Parse error: Unable to parse JSON string
I am really stuck on what the best way to accomplish it.
thanks in advance.
You want the first element of each nested array, not the first element of the outer array. So use map().
let data = [
[{
"Id": "110d611c-54e4-4593-a835-def0f34ed882",
"duration": 30,
"name": "burger",
"price": 10,
}],
[{
"Id": "edc241e9-5caf-4f0b-b6ea-6cf5fc57d260",
"duration": 10,
"name": "Cake",
"price": 5,
}]
];
let newData = data.map(el => el[0]);
console.log(newData);
Removing the external bracket will result in an invalid javascript object.
To obtain a single array with all the objects you can use flatMap
data.flatMap(x => x)
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
The result that you want is not valid, instead you can get array of object using flat as:
data.flat()
let data = [
[
{
Id: "110d611c-54e4-4593-a835-def0f34ed882",
duration: 30,
name: "burger",
price: 10,
},
],
[
{
Id: "edc241e9-5caf-4f0b-b6ea-6cf5fc57d260",
duration: 10,
name: "Cake",
price: 5,
},
],
];
const result = data.flat();
console.log(result);

Insert key's value in the array of object having same key

Say I've an array of object:
const Info = [{
"id": "1aa2",
"details": [{
"name": "rusty",
"age": "12",
"favourite": [ObjectId("602b696cb783fc15845d015e"), ObjectId("602b696cb783fc15845d0112")]
}]
},
{
"id": "3aa2",
"details": [{
"name": "john",
"age": "122",
"favourite": [ObjectId("602b696cb783fc15845d0112s"), ObjectId("602b696cb783fc15845d01wqs")]
}]
}
]
I want to merge favourite in one array as:
["favourite": [
ObjectId("602b696cb783fc15845d015e"),
ObjectId("602b696cb783fc15845d0112"),
ObjectId("602b696cb783fc15845d0112s"),
ObjectId("602b696cb783fc15845d01wqs")
]
]
I tried using for loop but it's creating nasty nested for loop which is reducing performance a lot.
Basically, you need to iterate through Info collection, iterate through 'details' sub-collection, and copy all data into a new array. After, just create a new structure using favs variable content or paste this code as object value directly.
BTW your result array need's to contain an object at least, like that:
[ { favourite: [...] } ]
About nested structures, you should try https://lodash.com/docs/4.17.15#flatMapDeep (at least just check the code)
const Info = [{
"id": "1aa2",
"details": [{
"name": "rusty",
"age": "12",
"favourite": ['ObjectId("602b696cb783fc15845d015e")', 'ObjectId("602b696cb783fc15845d0112")']
}]
},
{
"id": "3aa2",
"details": [{
"name": "john",
"age": "122",
"favourite": ['ObjectId("602b696cb783fc15845d0112s")', 'ObjectId("602b696cb783fc15845d01wqs")']
}]
}
]
const favs = Info.reduce((acc, item) => {
item.details.forEach(detail => {
acc.push(...detail.favourite);
})
return acc;
}, []);
console.log(favs);

Replacing Data in Array

I am working on an angular application. I have an array as follows:
[{
"Name": "Andy"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda"
}]
I have another array which containes data as follows:
[
{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Billy",
"Id": "2",
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Ciena",
"Id": 5
"Time": "2020-06-19T11:05+00:00"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}
]
I want a resultant array such that code should check if Name is present in first array, then it should copy data from second array for that Name and push it in resultant array. For example common name between above two array is Andy and Doda, so data from Andy and Doda should be pushed to resultant array as follows:
[{
"Name": "Andy",
"Id": "1",
"Time": "2020-06-19T11:02+00:00"
},
{
"Name": "Bayer"
},
{
"Name": "James"
},
{
"Name": "Doda",
"Id": "4",
"Time": "2020-06-19T11:05+00:00"
}]
At run time I may get many names so code should be generic. I was trying following code which I got over stackoverflow itself
this.newArray = _.map(this.resultantArray, item => {
const value = _.find(this.dataArray, ['Name', item]);
const obj = value ? value : {Name: item};
return obj;
});
But this code is not working as expected as it works fine for the first time but when data comes for second time it appends data to previous data. I want array to be populated again freshly every time I send data. Please help
You can do this with vanilla JS no need for lodash. You can first map it and inside that you can find the value from second array otherwise return the current object:
var arrayTwo = [ { "Name": "Andy", "Id": "1", "Time": "2020-06-19T11:02+00:00" }, { "Name": "Billy", "Id": "2", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Ciena", "Id": "5", "Time": "2020-06-19T11:05+00:00" }, { "Name": "Doda", "Id": "4", "Time": "2020-06-19T11:05+00:00" } ];
var arrayOne = [{ "Name": "Andy"}, { "Name": "Bayer"}, { "Name": "James"}, { "Name": "Doda"}];
var result = arrayOne.map(val=>arrayTwo.find(p=>p.Name==val.Name) || val);
console.log(result);
Suppose first array name is First
First : any [] = [{"Name": "Andy"},{"Name": "Bayer"},{ "Name": "James"},{"Name": "Doda"}]
And Second array name is Second
Second : any[] = [{"Name": "Andy","Id": "1","Time": "2020-06-19T11:02+00:00"},{"Name": "Bayer"},{"Name": "James"},{"Name": "Doda","Id": "4","Time": "2020-06-19T11:05+00:00"}]
Now do looping and check each name of first if its exists in second copy from second and push in result array
result : any[] =[];
this.First.forEach((element) => {
let index = this.Second.findIndex((x) => element.Name== x.Name);
if (index > -1) {
let data = {
this.Second[index].Name,
this.Second[index].Id,
this.Second[index].time,
};
this.result.push(data);
}
}

Most performant way to sort a deeply nested array of objects by another deeply nested array of objects

As an example - I've included a one element array that contains an object that has a Children key, which is an array of objects and each object also has its' own Children key that contains another array.
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
{
"Id": "100",
"DisplayName": "1-2",
},
]
}
]
}
]
There is a second array of objects that I would like to compare the first array of objects to, with the intention of making sure that the first array is in the same order as the second array of objects, and if it is not - then sort until it is.
Here is the second array:
[
{
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "100",
"DisplayName": "1-2",
},
{
"Id": "10",
"DisplayName": "3-4",
},
{
"Id": "1000",
"DisplayName": "5-6",
},
]
}
]
}
]
The data that this will run on can be up in the tens of thousands - so performance is paramount.
What I'm currently attempting is using a utility method to convert each element of the second array into a keyed object of objects e.g.
{
1: {
"Id": "1",
"Children": [
{
"Id": "2",
"Children": [
{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}
]
}
}
This allows fast look up from the top level. I'm wondering if I should continue doing this all the way down or if there is an idiomatic way to accomplish this. I considered recursion as well.
The order of the already sorted array is not based on Id - it is arbitrary. So the order needs to be preserved regardless.
Assuming same depth and all Id's exist in each level of each object use a recursive function that matches using Array#findIndex() in sort callback
function sortChildren(main, other) {
other.forEach((o, i) => {
if (o.children) {
const mChilds = main[i].children, oChilds = o.children;
oChilds.sort((a, b) => {
return mChilds.findIndex(main => main.Id === a.Id) - mChilds.findIndex(main => main.Id === b.Id)
});
// call function again on this level passing appropriate children arrays in
sortChildren(mChilds, oChilds)
}
})
}
sortChildren(data, newData);
console.log(JSON.stringify(newData, null, ' '))
<script>
var data = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "3",
"DisplayName": "1-2",
},
{
"Id": "4",
"DisplayName": "3-4",
},
]
}]
}]
var newData = [{
"Id": "1",
"Children": [{
"Id": "2",
"Children": [{
"Id": "4",
"DisplayName": "3-4",
},
{
"Id": "3",
"DisplayName": "1-2",
},
]
}]
}]
</script>

Working With Dynamic Multidimensional key-value pairs in JSON

Having a thorny problem and only see similar but also simpler solutions on SO.
Is is possible to generate a dynamic key AND dynamic values using JS/JSON?
For instance, let's say I have JSON like this:
{
"email": "user#someco.com",
"firstname": "Bob",
"lastname": "Smith",
"company": "ACME",
"custom": {
"services": [
{
"name": "svc1",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc2",
"desc": "abcdefg",
"selected": "true",
"status": "None"
},
{
"name": "svc3",
"desc": "abcdefg",
"selected": "false",
"status": "None"
},
{
"name": "svc4",
"desc": "abcdefg",
"selected": "false",
"status": "None"
}
],
"fields": [
{
"name": "Products",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Product1",
"desc": "abcdef"
},
{
"name": "Product2",
"desc": "abcdef"
}
],
"services": [
"svc1",
"svc2",
"svc3"
]
},
{
"name": "Wines",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Wine 1",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
},
{
"name": "Fruits",
"desc": "abcdef",
"type": "multi",
"values": [
{
"name": "Fruit 1",
"desc": "abcdef"
},
{
"name": "Fruit 2",
"desc": "abcdef"
}
],
"services": [
"svc4"
]
}
]
}
};
I need to go into the fields and for each field (products, wines, fruits) see if a given service is contained within so that I can go back and generate a product or wine or fruit for each service that requires it. But I don't want to repeat the services names more than once. The resulting JSON should look something like this:
{"svc1":["Products"], "svc2":["Products"], "svc3":["Products"], "svc4":["Fruits", "Wines"]}
The hope would be that to generate a dynamic list in Angular I can just turn and loop back through this JSON, pulling out the values for each product, fruit, wine, whatever.
I've been trying a lot of nested for loops and the like but whenever I get more than one layer down the dynamism seems to stop. I'm guessing that for this to work I need to move between JS Objects and JSON?
Right now I'm trying something like this, which isn't quite working, stringify or no. And maybe I'm flip-flopping too much between JSON and JS Objects:
var outObj = [];
var fieldItems;
$.each(jsonObj.custom.fields, function(key, item) {
fieldItems = item;
fieldItems.name = item.name;
$.each(fieldItems.services, function(key, item) {
var serviceName = item;
//check to see if the serviceName already exists
if (outObj.indexOf(serviceName) > -1) {
outObj.serviceName.push(fieldItems.name);
} else {
outObj.push(serviceName);
}
});
});
JSON.stringify(outObj);
console.log("outObj " + outObj);
I get "can't read property 'push' of undefined" errors and the like. Seems this should be possible from a single nested loop, but maybe I need to just do two passes? Any other suggestions?
To me it sounds like overcomplicated solution. You can use basic array methods of javascript to filter out required structure. I am not sure what profiling_value in the presented snippet, so I started from the object structure in OP
var desiredResult = jsonObj.custom.services.reduce(function(result, service){
result[service.name] = jsonObj.custom.fields.filter(function(field){
return field.services.indexOf(service.name) >= 0;
}).map(function(field){ return field.name; });
return result;
}, {});
This gives the expected result for mentioned object.
reduce is required to iterate over all services and accumulate result in one object. Then for each service fields are iterated to filter out only those that contain link to this service. And finally list of filtered fields is transformed (map) into list of strings - their names - and inserted into accumulator

Categories

Resources