json filter nested array with javascript - javascript

I want to pull with javascript: {"subNav0", "subNav1", "subNav2", "subNav3", "subNav4", "subNav5"}.
my json:
var data = {
"menus":{
"GrandparentNav0":{
"name":"TopNav",
"items":[
{
"name":"ParentNav0",
"iconClass":"",
"items":[
{
"name":"ParentNav1",
"iconClass":"",
"items":[
{
"name":"subNav0",
"iconClass":""
},
{
"name":"subNav1",
"iconClass":""
},
{
"name":"subNav2",
"iconClass":""
},
{
"name":"subNav3",
"iconClass":""
},
{
"name":"subNav4",
"iconClass":""
},
{
"name":"subNav5",
"iconClass":""
}
]
},
]
}
]
}
},
};
i know basic filter of an array:
data .forEach(function(o) {
o.variable = o.variable.filter(s => s.value == value);
});
I dont know how to get through menus, GrandparentNav0 to pull the subNav(s)

By "pull the subNav(s)" do you mean like accessing it through something like bracket notation?
let subNavs = data['menus']['GrandparentNav0']['items'][0]['items']
console.log(subNavs)
/* would return
[
{
"name": "subNav0",
"iconClass": ""
},
{
"name": "subNav1",
"iconClass": ""
},
{
"name": "subNav2",
"iconClass": ""
},
{
"name": "subNav3",
"iconClass": ""
},
{
"name": "subNav4",
"iconClass": ""
},
{
"name": "subNav5",
"iconClass": ""
}
]
*/

Here is a solution using object-scan. This might be overkill for your requirements, however as you run into other use cases it's a Swiss army knife that makes these types of data interactions very clean
// const objectScan = require('object-scan');
const data = { menus: { GrandparentNav0: { name: 'TopNav', items: [ { name: 'ParentNav0', iconClass: '', items: [ { name: 'ParentNav1', iconClass: '', items: [ { name: 'subNav0', iconClass: '' }, { name: 'subNav1', iconClass: '' }, { name: 'subNav2', iconClass: '' }, { name: 'subNav3', iconClass: '' }, { name: 'subNav4', iconClass: '' }, { name: 'subNav5', iconClass: '' } ] } ] } ] } } };
const result = objectScan(['menus.GrandparentNav0.items[0].items[0].items[*].name'], { reverse: false, rtn: 'value' })(data);
console.log(result);
// => [ 'subNav0', 'subNav1', 'subNav2', 'subNav3', 'subNav4', 'subNav5' ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#14.0.0"></script>
Disclaimer: I'm the author of object-scan

Related

I need to filter an array of object that contains an array of object

So here's my data, I need to reduce? or filter it based on the given search string.
const contents = [
{
title: "Accounts",
links: [
{
header: "Accounts by Status",
},
],
},
{
title: "Executions",
links: [
{
header: "Purchase and Sales",
},
{
header: "AMLA Transactions Proof List",
},
{
header: "Account Ranking",
},
{
header: "Trading Summary",
},
],
},
];
const search = "account";
console.log(
contents.filter((content) =>
content.links.some((link) =>
link.header.toLowerCase().includes(search.toLowerCase())
)
)
);
.as-console-wrapper { max-height: 100% !important; }
Can someone guide me in the right direction? I think reduce with filter can do the job but I don't know where to start. Thanks!
If my search string is 'account'
My desired output should be something like this
[{
title: 'Accounts',
links: [{
header: 'Accounts by Status'
}]
},
{
title: 'Executions',
links: [{
header: 'Account Ranking'
}]
}
]
You need to rebuild content with links, if they match.
const
contents = [{ title: 'Accounts', links: [{ header: 'Accounts by Status' }] }, { title: 'Executions', links: [{ header: 'Purchase and Sales' }, { header: 'AMLA Transactions Proof List' }, { header: 'Account Ranking' }, { header: 'Trading Summary' }] }],
search = 'account',
result = contents.flatMap(content => {
const links = content.links.filter(({ header }) => header
.toLowerCase()
.includes(search.toLowerCase())
);
return links.length
? { ...content, links }
: [];
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This solution filters the links array by search string, and if non is found removes the item all together. The test input contains one more item that produces no hit: { title: 'No hit', links: [{ header: 'Something else' }] }
const input = [
{ title: 'Accounts', links: [{ header: 'Accounts by Status' }] },
{ title: 'Executions', links: [{ header: 'Purchase and Sales' }, { header: 'AMLA Transactions Proof List' }, { header: 'Account Ranking' }, { header: 'Trading Summary' }] },
{ title: 'No hit', links: [{ header: 'Something else' }] }
];
const searchString = 'account';
// for performance perform lowercase once ahead of time:
const search = searchString.toLowerCase();
const result = input.map(obj => {
let arr = obj.links.filter(o => o.header.toLowerCase().includes(search));
if(arr.length) {
// don't change original input, but return a filtered copy
return {
title: obj.title,
links: arr
};
} else {
return null;
}
}).filter(Boolean);
console.log(result);

Convert multiple json object into array of object

My data is currently stored in this format:
{
"Site1":{
"week":[
{
"access":1
},
{
"access":8
}
]
},
"Site2":{
"week":[
{
"access":16
}
]
},
"Site3":{
"week":[
{
"access":2
},
{
"access":6
},
{
"access":2
}
]
}
}
And I need to convert it into this format:
[
{
"id":"Site1",
"access":[1,8]
},
{
"id":"Site2",
"access":[16]
},
{
"id":"Site3",
"access":[2,6,2]
}
]
As you can see, I also need to take the keys (site name) and make them the "id" values.
Any ideas on how I can do this in JavaScript (I'm using angular v9)? I'm not very good at restructuring that type of data.
You can first take entries and then map it:
var data={ "Site1":{ "week":[ { "access":1 }, { "access":8 } ] }, "Site2":{ "week":[ { "access":16 } ] }, "Site3":{ "week":[ { "access":2 }, { "access":6 }, { "access":2 } ] }};
var result = Object.entries(data).map(([k,v])=>({id:k, access: v.week.map(p=>p.access)}));
console.log(result);
Object.keys()
map()
const data = {
Site1: {
week: [
{
access: 1,
},
{
access: 8,
},
],
},
Site2: {
week: [
{
access: 16,
},
],
},
Site3: {
week: [
{
access: 2,
},
{
access: 6,
},
{
access: 2,
},
],
},
};
const result = Object.keys(data).map(key => ({
id: key,
access: data[key].week.map(w => w.access),
}));
console.log(result);
you can simply use this code for your desired result.
Object.keys(data).map(key => (
{
id: key,
access: data[key].week.map(obj => obj.access),
}
))
Let me know if you face any issue.

How to add objects to an array during creation using a loop in Javascript?

I am trying to write some meta information for a website (using vue-meta) and I need to add some tags as objects within an array named meta.
The code is like this:
metaInfo() {
return {
htmlAttrs: { lang: "en"
},
title: this.Post.Title,
meta: [
{
name: "description", content: this.Post.Title
},
{
name: "date", content: this.Post.DateCreated
},
{
name: "author", content: this.Post.Author
},
// Now I need multiple objects of: {name: "tag", content: "Tags.TagName"} like this but doesn't work:
function() {
this.Tags.forEach(function (TagName, index) {
{ property: "tag", content: "TagName" }
})
}
],
}
}
How can I create my array so that I end up with this for example:
meta: [
{
name: "description", content: "Javascript question"
},
{
name: "date", content: "20200421"
},
{
name: "author", content: "volumeone"
},
{ property: "tag", content: "Javascript" }
,
{ property: "tag", content: "Programming" }
,
{ property: "tag", content: "Newbie" }
]
you can do such sort of thing.
var meta = [{
name: "description", content: this.Post.Title
},
{
name: "date", content: this.Post.DateCreated
},
{
name: "author", content: this.Post.Author
}]
this.Tags.forEach(function (TagName, index) {
meta.push({ property: "tag", content: "TagName" })
})
metaInfo() {
return {
htmlAttrs: { lang: "en"
},
title: this.Post.Title,
// or you can just write "meta" instead of "meta: meta" its an shorthand // code
meta: meta
}
}
Unless I'm missing something, you can just use push and pass the object.
var meta = [];
meta.push({"property" : "tag","content" : "test"});
console.log(meta);

Find the value and delete the whole object associated with that array from a deeply nested array of object

I browsed So many questions to find out logics for finding Index in a deeply nested array of object, I didn't find it useful for my requirement though.
in search of Solution in Javascript, Lodash/Underscore would be Fine too.
Let me just phrase out the Whole requirement, Hoping I get a path to find the solution for this issue.
Requirement:
I have an array of objects
arrObj =[
{
"id":3208,
"name":"List",
"issueResponses":[
],
"isActive":false
},
{
"id":3209,
"name":"Me",
"issueResponses":[
],
"isActive":false
},
{
"id":3314,
"name":"SNew",
"issueResponses":[
],
"isActive":false
},
{
"id":3315,
"name":"Olive",
"issueResponses":[
{
"id":3282,
"name":"related to Olive",
"issueResponses":[
],
"isActive":false
},
{
"id":3316,
"name":"My olives are not yet picked",
"issueResponses":[
{
"id":3317,
"name":"Pickup Not Done",
"issueResponses":[
],
"isActive":false
}
]
}
]
}
]
As we can see its deeply nested, I have another array
delValue = [3317,3282], And tomorrow it might be anything in these Deep Nesting.
I have to find these delValue arrays in arrObj and delete all those Objects which has "id" as these Values.
I am trying to solve this in a generic way which can support any number deep search Level and Deletion of the Object from that.
Please help me out in this, if More Information needed will be happy to provide.
You can use filter to achieve this:
function removeDeletions(array, deletion) {
return array.filter(el => {
if (Array.isArray(el.issueResponses)) el.issueResponses = removeDeletions(el.issueResponses, deletion);
return ! deletion.includes(el.id);
})
}
DEMO:
let arrObj = [{
"id": 3208,
"name": "List",
"issueResponses": [
],
"isActive": false
},
{
"id": 3209,
"name": "Me",
"issueResponses": [],
"isActive": false
},
{
"id": 3314,
"name": "SNew",
"issueResponses": [
],
"isActive": false
},
{
"id": 3315,
"name": "Olive",
"issueResponses": [{
"id": 3282,
"name": "related to Olive",
"issueResponses": [
],
"isActive": false
},
{
"id": 3316,
"name": "My olives are not yet picked",
"issueResponses": [{
"id": 3317,
"name": "Pickup Not Done",
"issueResponses": [
],
"isActive": false
}]
}
]
}
]
let delValue = [3317, 3282];
function removeDeletions(array, deletion) {
return array.filter(el => {
if (Array.isArray(el.issueResponses)) el.issueResponses = removeDeletions(el.issueResponses, deletion);
return !deletion.includes(el.id);
})
}
console.log(removeDeletions(arrObj, delValue));
Just keep checking issueResponses - like so:
function deleteIssueResponses(issues, ids) {
for (let i = issues.length; i >= 0; i--) {
if (issues[i].issueResponses.length) {
deleteIssueResponses(issues[i].issueResponses, ids);
}
if (ids.contains(issues[i].id)) {
issues.splice(i, 1);
}
}
}
And call it:
deleteIssueResponses(arrObj, [3317,3282]);
This should be quite simple to solve with some recursion. This function will delete the given ids in the array passed to it, or else call itself to do the same for the nested arrays.
function deleteIds(arr, ids) {
for (let i = 0; i < arr.length; i++) {
if (ids.indexOf(arr[i].id) !== -1) {
arr.splice(i, 1);
i--;
} else {
deleteIds(arr[i].issueResponses, ids);
}
}
}
Call with deleteIds(arrObj, delValue) as in your question.
We use object-scan for basic data processing tasks like this. Once you wrap your head around how to use it, it's pretty good and powerful. Here is how you could answer your questions:
// const objectScan = require('object-scan');
const prune = (values, data) => objectScan(['**[*].id'], {
rtn: 'count',
filterFn: ({ gparent, gproperty, value }) => {
if (values.includes(value)) {
gparent.splice(gproperty, 1);
return true;
}
return false;
}
})(data);
const arrObj = [{ id: 3208, name: 'List', issueResponses: [], isActive: false }, { id: 3209, name: 'Me', issueResponses: [], isActive: false }, { id: 3314, name: 'SNew', issueResponses: [], isActive: false }, { id: 3315, name: 'Olive', issueResponses: [{ id: 3282, name: 'related to Olive', issueResponses: [], isActive: false }, { id: 3316, name: 'My olives are not yet picked', issueResponses: [{ id: 3317, name: 'Pickup Not Done', issueResponses: [], isActive: false }] }] }];
console.log(prune([3317, 3282], arrObj)); // return number of deletes
// => 2
console.log(arrObj);
// => [ { id: 3208, name: 'List', issueResponses: [], isActive: false }, { id: 3209, name: 'Me', issueResponses: [], isActive: false }, { id: 3314, name: 'SNew', issueResponses: [], isActive: false }, { id: 3315, name: 'Olive', issueResponses: [ { id: 3316, name: 'My olives are not yet picked', issueResponses: [] } ] } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#15.0.0"></script>
Disclaimer: I'm the author of object-scan

Meteor cross collection arrays

I am trying to pull an array from a different collection using collection2. I have been able to do this with objects using the following example for users:
users: {
type: String,
label: "Inspector",
optional: true,
autoform: {
firstOption: 'Choose an Inspector',
options: function() {
return Meteor.users.find({}, {
sort: {
profile: 1,
firstName: 1
}
}).map(function(c) {
return {
label: c.profile.firstName + " " + c.profile.lastName,
value: c._id
};
});
}
}
},
I would like to do the same but for an array of objects. Here is what the source data looks like:
{
"_id": "xDkso4FXHt63K7evG",
"AboveGroundSections": [{
"sectionName": "one"
}, {
"sectionName": "two"
}],
"AboveGroundItems": [{
"itemSection": "one",
"itemDescription": "dfgsdfg",
"itemCode": "dsfgsdg"
}, {
"itemSection": "two",
"itemDescription": "sdfgsdfg",
"itemCode": "sdfgsdgfsd"
}]
}
Here is what my function looks like:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options: function() {
return TemplateData.find({}, {
sort: {
AboveGroundSections: 1,
sectionName: [0]
}
}).map(function(c) {
return {
label: c.AboveGroundSections.sectionName,
value: c.AboveGroundSections.sectionName
}
});
}
}
},
I know this, it's just not pulling the data for me. I am sure, I am just missing something small. I am trying to pull all objects within the AboveGroundSection array.
Your .map() is iterating over the set of documents but not over the arrays inside each document. Also I don't think your sorting is going to work the way you hope because of the inner nesting.
Try:
agSection: {
type: String,
optional: true,
autoform: {
firstOption: 'Select A Section Type',
options() {
let opt = [];
TemplateData.find().forEach(c => {
c.AboveGroundSections.forEach(s => { opt.push(s.sectionName) });
});
return opt.sort().map(o => { return { label: o, value: o } });
}
}
},
Also if your AboveGroundSections array only has a single key per element then you can simplify:
"AboveGroundSections": [
{ "sectionName": "one" },
{ "sectionName": "two" }
]
To:
"AboveGroundSections": [
"one",
"two"
]

Categories