Not getting whole flattened javascript object structure - javascript

I have a nested object that I wish to retrieve certain key/value pairs from. For these to be retrieved they must have a value for each key.
I'm close, but I'm not getting any of the nested objects' key/value pairs.
I have created this fiddle
Here's the function I have at present:
function getKeysVals(obj, keys, recurse = false)
{
let addToOutput = true;
let out = [];
let cnt = 0;
obj.map
(
(thisObj) =>
{
let newObj = {}; // Temp holder for new object that gets added to output.
// Loop through the requested keys, adding them to the new object:
for( i in keys)
{
// Check that this key has a value:
if(!thisObj[keys[i]])
{
addToOutput = false;
break;
}
else
{
newObj[keys[i]] = thisObj[keys[i]];
}
}
// Ensure we have values for ALL the requested keys in this object:
if( addToOutput ) out.push(newObj);
// Go round again if this object has the specified recurse object:
if( thisObj[recurse] )
{
getKeysVals(thisObj[recurse], keys, recurse)
}
}
);
return out
}
When I call it with result = getKeysVals(nodes[0].nodes, ['id', 'text', 'filePath'], 'nodes'); I expect to get a new array with:
[
{ id: 1526297185466,​​​​​ text: 'test part a',​​​​​ filePath: 'test part a-1526297185451.CSV' },
{ id: 1526297202132,​​​​​ text: 'test part B',​​​​​ filePath: 'test part B-1526297202118.CSV' },​​​​​
{ id: 1526297209980,​​​​​ text: 'Test Part C',​​​​​ filePath: 'Test Part C-1526297209966.CSV' }
]
But I only get:
[{ id: 1526297185466,​​​​​ text: 'test part a',​​​​​ filePath: 'test part a-1526297185451.CSV' }]
The whole object:
[{
"id": 1526297177970,
"text": "k",
"nodes": [
{
"id": 1526297185466,
"tags": [1],
"text": "test part a",
"state": { "checked": true, "expanded": true },
"filePath": "test part a-1526297185451.CSV"
},
{
"id": 1526297195199,
"tags": [1],
"text": "New Product Set",
"nodes": [
{
"id": 1526297202132,
"tags": [1],
"text": "test part B",
"state": { "checked": true, "expanded": true },
"filePath": "test part B-1526297202118.CSV"
},
{
"id": 1526297209980,
"tags": [1],
"text": "Test Part C",
"state": { "checked": true, "expanded": true },
"filePath": "Test Part C-1526297209966.CSV"
}
],
"state": { "checked": true }
}
],
"state": { "checked": true }
}]

If you call
getKeysVals(thisObj[recurse], keys, recurse)
This will create a new out and return that, so you may add that to the current out:
out.push(...getKeysVals(thisObj[recurse], keys, recurse));

Related

Parsing out data from json

Wrecking my head today trying to find out how to loop through and log out the name of each object.
Here is the JSON response:
{
"placeListings": {
"OBJ1": {
"Active": true,
"Name": "place 1"
},
"OBJ2": {
"Active": true,
"Name": "place 2"
},
"OBJ3": {
"Active": true,
"Name": "place 3"
}
}
}
I would like to parse out the "Name" part in a for loop
for (let i = 0; i < res.length; i++) {
console.log("NAME: " + res.placeListings.OBJ1.Name);
}
But I don't know how to iterate through OBJ1/OBJ2/OBJ3 etc..
Any help is welcome!
The placeListings is an object, not an array.
So you need to use the Object.keys method to get the object's keys
const source = {
placeListings: {
OBJ1: {
Active: true,
Name: 'place 1'
},
OBJ2: {
Active: true,
Name: 'place 2'
},
OBJ3: {
Active: true,
Name: 'place 3'
}
}
}
const keys = Object.keys(source.placeListings)
console.log(keys)
for (let i = 0; i < keys.length; i++) {
console.log(source.placeListings[keys[i]])
}
You can simply achieve this with a single line of code by using Object.keys() and Array.forEach() method.
Demo :
const res = {
"placeListings": {
"OBJ1": {
"Active": true,
"Name": "place 1"
},
"OBJ2": {
"Active": true,
"Name": "place 2"
},
"OBJ3": {
"Active": true,
"Name": "place 3"
}
}
};
Object.keys(res.placeListings).forEach(key => console.log(res.placeListings[key].Name));

How to group an array of objects in javascript?

I'm trying to group an array of objects. The array should be grouped following this quote:
Group by type respecting the sequence.
Array I wish to group
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
The way I want it to be grouped:
var newArray = [
[
{type: "user", text: "user1"},
{type: "user", text: "user2"},
{type: "user", text: "user3"}
],
[
{type: "clerk", text: "clerk1"}
],
[
{type: "user", text: "user4"}
],
[
{type: "clerk", text: "clerk2"},
{type: "clerk", text: "clerk3"}
],
[
{type: "user", text: "user5"},
{type: "user", text: "user6"}
]
];
What i tried:
I'm trying to use a filter, but without success since it even groups, but it groups all that are of the same type without respecting the sequence I want (from the array above);
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
var newArray = [];
newArray.push(filtrarArray(arrayObj, 'clerk'));
newArray.push(filtrarArray(arrayObj, 'user'));
console.log(newArray);
function filtrarArray(array, type) {
return array.filter(function (val) {
return val.type === type;
});
}
The snippet below first sorts the array by type, which then makes it easy to loop through and group. Let me know if this solves your problem :)
EDIT
Just realized you didn't need sorting, so I commented the sort function out, but it's always there to be uncommented if you change your mind :)
const arrayObj = [
{ type: 'user', text: 'user1' },
{ type: 'user', text: 'user2' },
{ type: 'user', text: 'user3' },
{ type: 'clerk', text: 'clerk1' },
{ type: 'user', text: 'user4' },
{ type: 'clerk', text: 'clerk2' },
{ type: 'clerk', text: 'clerk3' },
{ type: 'user', text: 'user5' },
{ type: 'user', text: 'user6' },
];
const group = ar =>
ar
// .sort((a, b) => (a.type < b.type ? -1 : 1))
.reduce((newAr, obj, i) => {
if (0 === i) return [[obj]];
if (obj.type === newAr[newAr.length - 1][0].type)
return newAr[newAr.length - 1].push(obj), newAr;
return [...newAr, [obj]];
}, []);
const groupedAr = group(arrayObj);
console.log(groupedAr);
function groupConsecutive(arrayObj) {
if (arrayObj.length === 0) {
return [];
}
let matchedTypesIndex = 0;
let newArray = [
[
arrayObj[0]
]
];
let currentType = arrayObj[0]["type"];
let i = 1;
while (i < arrayObj.length) {
if (arrayObj[i]["type"] === currentType) {
newArray[matchedTypesIndex].push(arrayObj[i]);
} else {
currentType = arrayObj[i]["type"];
newArray.push([]);
matchedTypesIndex++;
newArray[matchedTypesIndex].push(arrayObj[i]);
}
i++;
}
return newArray;
}
This is probably not best pure solution but works as you need.
var arrayObj = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let lastType;
let arr = [];
let arrIndex = -1;
arrayObj.forEach(obj => {
if(obj.type == lastType) { // add item into last group array by index
arr[arrIndex].push(obj);
}
else { // or add new group array
lastType = obj.type;
arrIndex++;
arr.push([obj]);
}
})
console.log(arr);
See This solution it will work
var arrayObj = [
{ type: "user", text: "user1" },
{ type: "user", text: "user2" },
{ type: "user", text: "user3" },
{ type: "clerk", text: "clerk1" },
{ type: "user", text: "user4" },
{ type: "clerk", text: "clerk2" },
{ type: "clerk", text: "clerk3" },
{ type: "user", text: "user5" },
{ type: "user", text: "user6" },
];
let typeNow = arrayObj[0].type;
let res = [];
let resultArray = [];
arrayObj.forEach((obj, i) => {
if (obj.type == typeNow) {
resultArray.push(obj);
} else {
resultArray = [obj];
res.push(resultArray);
typeNow = obj.type;
}
if (i == arrayObj.length - 1) res.push(resultArray);
});
console.log(res);
This is best solution can i have
It seem unordred because of Browser auto order but if you try in js file it will work and ordred
I'm responding with another way I found to solve my problem. This is just one more way I decided to comment.
Let's go:
I'm traversing the arrayObjects array using the appropriate loop for arrays for...of and then checking if the variable I set for arrayObjects (loopArrObj) has a different value of type of the variable (typeValue), if it is inserted at the end of the new array (grouping) using the array method push an empty array and then assign the value of the loopArrObj(Ie, there will be in the array grouping array empty only for the values ​​that are different).
So far so good, we have the first empty array. Next I'm defining this empty array with the push method the loopArrObj object in question, then we get the value through the console. I'm removing 1 from grouping.lengh so the loop assigns from 0 and not 1.
var arrayObjects = [
{ "type": "user", "text": "user1" },
{ "type": "user", "text": "user2" },
{ "type": "user", "text": "user3" },
{ "type": "clerk", "text": "clerk1" },
{ "type": "user", "text": "user4" },
{ "type": "clerk", "text": "clerk2" },
{ "type": "clerk", "text": "clerk3" },
{ "type": "user", "text": "user5" },
{ "type": "user", "text": "user6" }
];
let typeValue,
grouping = [],
loopArrObj;
for (loopArrObj of arrayObjects) {
if (loopArrObj.type !== typeValue) {
grouping.push([]);
typeValue = loopArrObj.type;
}
grouping[grouping.length - 1].push(loopArrObj);
}
console.log(grouping);

Need help formatting array in JavaScript

I have a JavaScript array with the following format:
[
{
"header": true,
"id": "0",
"name": "dairy",
},
{
"category": "dairy",
"header": false,
"id": "-LSlje6ESGALGpckMhb7",
"name": "milk",
},
{
"category": "dairy",
"header": false,
"id": "-LSm9EpFg5DhW036aUle",
"name": "cheese",
},
{
"header": true,
"id": "3",
"name": "dessert",
},
{
"category": "dessert",
"header": false,
"id": "-LSm9MLZkrnvtPySw5U6",
"name": "cake",
},
{
"category": "dessert",
"header": false,
"id": "-LSmAQ0rdDLrpz0TSPuD",
"name": "pie",
},
{
"header": true,
"id": "6",
"name": "fruit",
},
{
"category": "fruit",
"header": false,
"id": "-LSlazVIGAKLakxAIa8G",
"name": "apple",
},
{
"category": "fruit",
"header": false,
"id": "-LSlb5GH6xZz-DpNVS22",
"name": "pear",
},
{
"category": "fruit",
"header": false,
"id": "-LSwWJldY1nxQrotyv-V",
"name": "strawberry",
},
{
"header": true,
"id": "10",
"name": "meat",
},
{
"category": "meat",
"header": false,
"id": "-LSljXQzfXthJbOA54Ah",
"name": "fish",
},
{
"category": "meat",
"header": false,
"id": "-LSmA2-R9pOY8abAUyST",
"name": "steak",
},
{
"category": "meat",
"header": false,
"id": "-LSmAJ4J4gIfVQ8sgPDa",
"name": "pork",
},
]
What I am trying to do, is map through this array, and transform it to the following format:
[
{
title: nameOfFirstHeader,
data: items.slice(indexOfFirstHeader, indexOfSecondHeader),
},
{
title: nameOfSecondHeader,
data: items.slice(indexOfSecondHeader, indexOfThirdHeader),
},
{
title: nameOfThirdHeader,
data: items.slice(indexOfThirdHeader, indexOfFourthHeader),
},...and so on
]
So basically there will be an object section for each 'header' that is found in the original array. Each object section data property will contain the items found between the first header and the second header, and so on, until there are no more headers. I really can't wrap my head around how I can do this. Here is a reference to the the module I am using: https://github.com/saleel/react-native-super-grid#sectiongrid-example
Thanks!
I think this may be what you're trying to accomplish...
var grouped = items.reduce((acc,obj)=>{
let {header, name} = obj;
if (header) return [...acc, { title:name, data:[] }] // either first matching header or new match. Add fresh 'header' object
if (!acc.length) return acc; //not header and none have passed. Do nothing
let allButLast = acc.slice(0, acc.length-1),
lastElem = acc[acc.length-1]; // not a header, but there is an existing match. Add it to last match's data array
return [
...allButLast,
{
...lastElem,
data:[...lastElem.data, obj]
}
]
},[])
but it seems unreliable to trust the order of an array for this purpose. It would probably be more reliable to match by isHeader.name === notHeader.category to be less presumptive about the order of data you're iterating over. Like this...
var grouped = items.reduce((acc,obj)=>{
let {header, name, category} = obj;
if (header) return [...acc, { title:name, data:[] }];
if (!acc.length) return acc;
return acc.map((elem)=>{
if (elem.title !== category) return elem;
return {
...elem,
data: [ ...elem.data, obj]
};
})
},[])
I think you can probably do something like
const data = [];
let activeIndexForData = -1;
for(let i = 0; i < dataToSort.length -1; i++) {
if(dataToSort[i].header) {
activeIndexForData++;
}
if(data.length < activeIndexForData - 1) {
data.push({ title: dataToSort[i].name, data# []})
}
else {
data[activeIndexForData].data.push({ title: dataToSort[i].name, data: [])
}
}

JS - Sorting child objects within an object

I am trying to find if there is a way to sort objects within an object using a bool value. I haven't been able to find anything to help, and not even sure if possible.
My object example is this:
{
"Music": {
"Key": "Music",
"Title": "Music",
"Icon": "t-music",
"Colour": "blue",
"Active": false
},
"The Arts": {
"Key": "The Arts",
"Title": "The Arts",
"Icon": "t-arts",
"Colour": "blue",
"Active": false
},
"Social": {
"Key": "Social",
"Title": "Social",
"Icon": "t-social",
"Colour": "yellow",
"Active": true
}
}
Is there anyway to sort these objects within the parent object based on the "Active" bool?
Though objects don't have a sort order, you can organize these objects in an array based on the Active bool. Use .sort() and .map().
var obj = {
"Music": {
"Key": "Music",
"Title": "Music",
"Icon": "t-music",
"Colour": "blue",
"Active": false
},
"The Arts": {
"Key": "The Arts",
"Title": "The Arts",
"Icon": "t-arts",
"Colour": "blue",
"Active": true
},
"Social": {
"Key": "Social",
"Title": "Social",
"Icon": "t-social",
"Colour": "yellow",
"Active": true
}
};
var sorted = Object.keys(obj) // ["Music", "The Arts", "Social"]
.sort(function(a, b) {
return obj[b].Active - obj[a].Active; // Organize the category array
})
.map(function(category) {
return obj[category]; // Convert array of categories to array of objects
});
The concept of order in an object doesn't exist, but you can shuffle the entries visually by turning the elements into an array, sorting it, and making a new object from that.
You can sort from a nested value by using Array#sort and passing it a function.
let arr = Object.entries(obj).sort(([key1, val1], [key2, val2]) => val2.Active)
arrayToObject = array => {
let newObj = {}
array.forEach(([key, val]) => {
newObj[key] = val
})
return newObj
}
console.log(arrayToObject(arr))
// { Social:
// { Key: 'Social',
// Title: 'Social',
// Icon: 't-social',
// Colour: 'yellow',
// Active: true },
// Music:
// { Key: 'Music',
// Title: 'Music',
// Icon: 't-music',
// Colour: 'blue',
// Active: false },
// 'The Arts':
// { Key: 'The Arts',
// Title: 'The Arts',
// Icon: 't-arts',
// Colour: 'blue',
// Active: false } }
Thanks Guys,
I wasn't sure if objects could be sorted but never hurts to ask.
Borja's answer worked for me, but only once i used Thomas' 'obj[b].Active - obj[a].Active' in place of '!obj[a].Active && obj[b].Active'.
I have only just seen Andrew's response and will test that out also.

Looping through an array of objects

I have the array of objects called res and am trying to loop through and organize the objects based on having one href, one method, and in some cases multiple schema, as with:
href: '/questions/{id}'
My issue is when I have multiple schema, if the current object I am in has '$schema' I want to check if the next object in the array also has '$schema'. If it does then I want to label the current schema object, requestSchema and the next object will be called responseSchema. But if the next object does not contain '$schema' then the current object will be labeled responseSchema.
I want to take res and turn it into
[{
"resource": "/questions",
"verb": "GET",
"schemaResponse": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"data": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"question": {
"type": "string",
"enum": [
"Favourite programming language?"
]
},
"published_at": {
"type": "string",
"enum": [
"2014-11-11T08:40:51.620Z"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1"
]
},
"choices": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"choice": {
"type": "string",
"enum": [
"Javascript"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1/choices/1"
]
},
"votes": {
"type": "number",
"enum": [
2048
]
}
},
"required": [
"choice",
"url",
"votes"
],
"additionalProperties": false
}]
}
},
"required": [
"question",
"published_at",
"url",
"choices"
],
"additionalProperties": false
}]
}
},
"required": [
"data"
]
}
}, {
"resource": "/questions/{id}",
"verb": "GET",
"schemaRequest": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"id": {
"type": "number"
}
},
"required": [
"id"
]
},
"schemaResponse": {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"question": {
"type": "string",
"enum": [
"Favourite programming language?"
]
},
"published_at": {
"type": "string",
"enum": [
"2014-11-11T08:40:51.620Z"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1"
]
},
"choices": {
"type": "array",
"items": [{
"type": "object",
"properties": {
"choice": {
"type": "string",
"enum": [
"Javascript"
]
},
"url": {
"type": "string",
"enum": [
"/questions/1/choices/1"
]
},
"votes": {
"type": "number",
"enum": [
2048
]
}
},
"required": [
"choice",
"url",
"votes"
],
"additionalProperties": false
}]
}
},
"required": [
"question",
"published_at",
"url",
"choices"
],
"additionalProperties": false
}
}
]
Everything works except for in the case of needing to have a request schema and a response schema.
const lodash = require('lodash');
var res = [
{ href: '/questions' },
{ method: 'GET' },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties: { data: [Object] },
required: [ 'data' ] },
{ href: '/questions/{id}',
hrefVariables: { element: 'hrefVariables', content: [Object] } },
{ method: 'GET',
headers: { element: 'httpHeaders', content: [Object] } },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties: { id: [Object] },
required: [ 'id' ] },
{ '$schema': 'http://json-schema.org/draft-04/schema#',
type: 'object',
properties:
{ question: [Object],
published_at: [Object],
url: [Object],
choices: [Object] },
required: [ 'question', 'published_at', 'url', 'choices' ] } ]
var arr = [];
var arrFinal = [];
var result = {};
for (var key = 0; key < res.length; key++) {
console.log(res[key]);
console.log(key);
var found = false;
for(var i = 0; i < arr.length; i++) {
//console.log((lodash.has(res[key], 'href')));
//console.log((lodash.has(res[key-1], '$schema')));
if ((lodash.has(arr[i], 'href'))) {
found = true;
break;
}
}
if ((lodash.has(res[key], '$schema')) && (lodash.has(res[key-1], '$schema'))) {
console.log('here');
result.schemaResponse = res[key];
result = lodash.omit(result, ['headers', 'properties', 'hrefVariables', 'required', 'href', 'method']);
break;
}
if((found === true) && (lodash.has(res[key], '$schema'))) {
var result = {};
console.log('there')
var combinedKeys = arr.reduce(function(a, item) {
Object.keys(item).map(function(key) {
if(key === 'href'){
result.resource = item[key];
}
if(key === 'method'){
result.verb = item[key];
} else {
result[key] = item[key];
}
});
return result;
}, {});
arr = [];
if((lodash.has(res[key+1], '$schema'))){
result.schemaRequest = res[key];
} else {
result.schemaResponse = res[key];
result = lodash.omit(result, ['headers', 'properties', 'hrefVariables', 'required', 'href', 'method']);
arrFinal.push(result);
result = {};
}
}
else {
console.log('hmmm');
var object = res[key];
arr.push(object);
}
}
var string = JSON.stringify(arrFinal, null, ' ')
console.log(arrFinal)
Based on this:
My issue is when I have multiple schema, if the current object I am in has '$schema' I want to check if the next object in the array also has '$schema'. If it does then I want to label the current schema object, requestSchema and the next object will be called responseSchema. But if the next object does not contain '$schema' then the current object will be labeled responseSchema.
and this (from my comment on your question):
Your question was a little unclear (I'd suggest proofreading it again and breaking up some of the run-on sentences). Are you saying that when you evaluate if ((lodash.has(res[key], '$schema')) && (lodash.has(res[key-1], '$schema'))) the value res[key-1] is always undefined?. So basically the 2nd if block never executes
Here is some pseudo-code to work into your code:
for ( var nIdx, crnt, next, key = 0, m = res.length; key < m; key++ ){
crnt = res[ key ]
next = res[ key + 1 ]
//do your checking here based on the existence of 'next'
if (next){ .... }
}
I'd test this on a simple loop and log the values of crnt and next to see if you're actually getting the expected results. If they are as expected, you can adjust your code to use those values instead of trying to access them dynamically with res[ key ] further down in your code.
I dunno, what the issue really is with your code, but this will be more readable at the least and will probably illuminate your error.

Categories