Replace property of a nested object by matching its key - javascript

I have an object of the following kind
let obj = {
"p1" : "main",
"p2" : {
"p21" : [
{
"key1" : "val1",
"value1" : "val2",
},
{
"prop" : "test",
"value" : "dummy"
}
]
}
}
Need to find the "prop", and if its present set the "value" to empty string. Note there might be any number objects inside "p21" and in any order. Just need to find "prop" and then update "value" to empty string
Have tried the following
obj.p2.p21.map((item) => {
if (item.hasOwnProperty("prop")) {
item.value = "";
}
})

You need to create a function to check the key and then replace value.
let obj = {
"p1": "main",
"p2": {
"p21": [{
"key1": "val1",
"value1": "val2",
},
{
"prop": "test",
"value": "dummy"
}
]
}
}
function replaceValue(item) {
for (var i in item) {
if (i == "prop") {
item["value"] = "";
break;//break if you only want to place the first , otherwise remove it
}
}
}
obj.p2.p21.map(item => replaceValue(item));
console.log(obj);
.as-console {
height: 100% !important;
}

obj.p2.p21.map((elem) => {
if(Object.keys(elem)[0] === "prop")
elem.value = ""
})
try something like that?

Related

How to remove empty object in array?

I am trying to remove the empty object {} from the below structure.
data = [{
"total" : "value",
"status" : "statusVal",
"recs" : [{
"total" : "value",
"region" : "name",
"recs" : [{},{
"recs" : [{
"recs" : [{
"value" : "a",
"label" : "fn"
}]
}]
}]
}]
}]
This is my JavaScript code where I process the data and trying to remove the empty object from the result.
var result = json.parse(data);
for(var i=0;i<result.length;i++){
if(result[i].hasOwnProperty("recs")){
var fset = result[i].recs;
for(var j=0;j<fset.length;j++){
if(fset[j].recs === undefined || fset[j].recs === null){
delete fset[j].recs;
}
if(fset[j].hasOwnProperty("recs")){
var sset = fset[i].recs;
for(var k=0;k<sset.length;k++){
var tset = sset[i].recs;
if(sset[k].hasOwnProperty("recs")){
for(var z=0;z<tset.length;z++){
if(tset[z].hasOwnProperty("recs")){
// logic to push
}
}
}
}
}
}
}
}
I tried checking null and undefined and also with property check bool as false. Since the empty {} is always returning length as 1, that is also ruled out. I am stuck here on processing the removal of empty object.
Above code is removing the entire recs node. Can you help me find what I am missing?
Check the length of the Object.keys() to see if object is empty or not.
Object.keys(fset[j].recs).length === 0
You can't iterate all the dynamic levels of array manually, so better to write the function which has recursive function call.
var data = [{
"total": "value",
"status": "statusVal",
"recs": [{
"total": "value",
"region": "name",
"recs": [{}, {
"recs": [{
"recs": [{
"value": "a",
"label": "fn"
}]
}]
}]
}]
}]
function removeEmpty(ary) {
ary.forEach((item, index) => {
if (Object.keys(item).length === 0) { ary.splice(index, 1); }
else if (item.recs && item.recs.length > 0)
removeEmpty(item.recs)
});
}
removeEmpty(data)
console.log(data)

How to get index of a nested field in JSON object using Loadash?

I have JSON object that looks like the snippet below.
I can navigate to the fields that I am interested to query, which match the pattern useful*
contents[0].mainArea[1].rec[0].attributes['useful.k1']
contents[0].mainArea[1].rec[1].attributes['useful.k1']
Is it possible to write a Lodash command that can extract/return the indices in bold above? I need the indices as I will later use these indices to create an assertion.
I am not sure where to start looking. Any ideas as to which commands I need to consider will be greatly appreciated.
{
"contents": [
{
"leftArea": [],
"mainArea": [
{
"key11": "val11",
"key12": [
{
"subkey11": "subValue11",
"subkey12": "subValue12"
},
{
"subkey21": "subValue21",
"subkey22": "subValue22"
}
]
},
{
"key21": "val21",
"rec": [
{
"attributes": {
"useful.k1": [
"value"
],
"useful.k2": [
"value"
],
"useful.k3": [
"value"
]
}
},
{
"attributes": {
"useful.k1": [
"value"
],
"useful.k2": [
"value"
],
"useful.k3": [
"value"
]
}
},
{
"notuseful": "value",
"notuseful2": [
{
"key1": "value",
"key2": "value"
},
{
"key1": "value",
"key2": "value"
},
{
"key1": "value",
"key2": "value"
}
]
}
]
}
]
}
]
}
I don't know if there is any specific lodash command for your problem, but you can use some functions to find your desired indices by some code like below:
const keys = require('lodash/keys');
function findUsefulKeys(data) {
const indices = [];
for (let i = 0; i < data.contents.length; i++) {
const mainAreaIndiesWithUsefulKeys = findUsefulKeysInContent(data.contents[i]);
if (mainAreaIndiesWithUsefulKeys.length > 0) {
indices.push({
contentIndex: i,
mainAreaIndices: mainAreaIndiesWithUsefulKeys
});
}
}
return indices;
}
function findUsefulKeysInContent(content) {
const mainAreaIndices = [];
if (!content.mainArea || !content.mainArea.length || content.mainArea.length === 0) {
return mainAreaIndices;
}
for (let i = 0; i < content.mainArea.length; i++) {
const recIndices = findRecsWithUsefulKeysInMainArea(content.mainArea[i]);
if (recIndices.length > 0) {
mainAreaIndices.push({
mainAreaIndex: i,
recIndices: recIndices
});
}
}
return mainAreaIndices;
}
function findRecsWithUsefulKeysInMainArea(mainArea) {
const recIndices = [];
if (!mainArea.rec || !mainArea.rec.length || mainArea.rec.length === 0) {
return recIndices;
}
for (let i = 0; i < mainArea.rec.length; i++) {
if (recHasUsefulKeys(mainArea.rec[i])) {
recIndices.push(i);
}
}
return recIndices;
}
function recHasUsefulKeys(rec) {
if (!rec || !rec.attributes) {
return false;
}
const attributeKeys = keys(rec.attributes);
for (let i = 0; i < attributeKeys.length; i++) {
if (attributeKeys[i].startsWith('useful')) {
return true;
}
}
return false;
}
// data is you json data
const data = require('./data');
console.log(JSON.stringify(findUsefulKeys(data)));
The above code with your example json data will print
[{"contentIndex":0,"mainAreaIndices":[{"mainAreaIndex":1,"recIndices":[0,1]}]}]
You can loop to get the value from JSON like below:
const data = {
"contents": [
{
"leftArea": [],
"mainArea": [
{
"key11": "val11",
"key12": [
{
"subkey11": "subValue11",
"subkey12": "subValue12"
},
{
"subkey21": "subValue21",
"subkey22": "subValue22"
}
]
},
{
"key21": "val21",
"rec": [
{
"attributes": {
"useful.k1": [
"value"
],
"useful.k2": [
"value"
],
"useful.k3": [
"value"
]
}
},
{
"attributes": {
"useful.k1": [
"value"
],
"useful.k2": [
"value"
],
"useful.k3": [
"value"
]
}
},
{
"notuseful": "value",
"notuseful2": [
{
"key1": "value",
"key2": "value"
},
{
"key1": "value",
"key2": "value"
},
{
"key1": "value",
"key2": "value"
}
]
}
]
}
]
}
]
}
const useful = data.contents[0].mainArea[1].rec;
for(const v in useful)
{
//console.log(useful[v].attributes); // Oject
for( let vv in useful[v].attributes) // for for every single value
{
console.log(useful[v].attributes[vv]);
}
}

Extract keys from object and nested array

I have an array of objects, those objects also have in some cases nested arrays, which contain objects.
Each object as a property key which I need to extract.
An example of the JSON I am dealing with is...
{
"items": [
{
"key":"main",
"foo":"bar",
"children":[
{
"key":"one",
"foo":"barboo"
},
{
"key":"two",
"foo":"boobaz"
}
]
},
{
"key":"secondary",
"foo":"baz",
"children":[
{
"key":"one",
"foo":"barboobaz"
},
{
"key":"two",
"foo":"boobazfoo"
}
]
}
]
}
Currently I am mapping over items and returning key, then where I find children I am mapping again returning key.
Something like this pseudo code...
class SomeClass {
let contentKeys = []
extractKeys = navItems => {
navItems.map(item => this.appendToContentRequest(item));
return this.contentKeys.join(',');
};
appendToContentRequest(item) {
if (~!this.contentKeys.indexOf(item.key)) {
this.contentKeys.push(item.key);
}
if (item.children) {
item.children.map(child => this.appendToContentRequest(child));
}
}
}
I don't like this though, it feels very 'hacky' and not very functional.
Is there a better way to achieve this?
You can use below recursive function to take any key's value of any nested array of objects
function extract(array, keyName) {
return array.reduce((a, b) =>
a.concat(...Object.keys(b).map(e => e === keyName ? b[e] : (Array.isArray(b[e]) ? extract(b[e], keyName) : null))), []).filter(e => e);
}
console.log(extract(obj.items, 'key'));
<script>
const obj = {
"items": [{
"key": "main",
"foo": "bar",
"children": [{
"key": "one",
"foo": "barboo"
},
{
"key": "two",
"foo": "boobaz"
}
]
},
{
"key": "secondary",
"foo": "baz",
"children": [{
"key": "one",
"foo": "barboobaz"
},
{
"key": "two",
"foo": "boobazfoo"
}
]
}
]
}
</script>
var data = {
"items": [
{
"key":"main",
"foo":"bar",
"children":[
{
"key":"one",
"foo":"barboo"
},
{
"key":"two",
"foo":"boobaz"
}
]
},
{
"key":"secondary",
"foo":"baz",
"children":[
{
"key":"one",
"foo":"barboobaz"
},
{
"key":"two",
"foo":"boobazfoo"
}
]
}
]
}
function flatNestedKey(array) {
var result = [];
const context = this;
array.forEach(function (a) {
result.push(a.key);
if (Array.isArray(a.children)) {
result = result.concat(context.flatNestedKey(a.children));
}
});
return result;
}
var keys = flatNestedKey(data.items);
console.log(keys);

Javascript nested object filtering create new object

Suppose I have object
let x = { "people" :{
"Sally": "value",
"Bob" : "other value"
},
"cars" :{
"Saab" : "this",
"Chevy": "that"
},
"trees":{
"Birch" : "what",
"Oak" : "where"
}
}
I want to search, so if I searched for "S" I'd get back an array that was
{ "people" :{
"Sally": "value",
},
"cars" :{
"Saab" : "this",
}
}
And if I searched for "b" I'd get:
{ "people" :{
"Bob" : "other value"
},
"trees":{
"Birch" : "what",
}
}
or "bo" would return
{ "people" :{
"Bob" : "other value"
}
And if I searched "e" I'd get
{ "cars" :{
"Chevy": "that"
}
}
Note that the "people" and "trees" isn't caught by the search for 'e'.
The strut will be of a fixed depth, and we only ever want to catch keys that match the filter and don't have children (we're also not interested in values that match, just keys).
Adding npm dependencies is acceptable.
Attempted solution:
filteredList(unfiltered,searchVal) {
return unfiltered.filter(search=> {
return search.toLowerCase().includes(searchVal.toLowerCase())
})
}
Obviously there's more to it, but I'm not sure which direction to proceed.
This is a basic attempt. It's seems work quite fine but I'm very sure that it may be possible to make even better. But I don't know how.
let x = {
"people": {
"Sally": "value",
"Bob": "other value"
},
"cars": {
"Saab": "this",
"Chevy": "that"
},
"trees": {
"Birch": "what",
"Oak": "where"
}
}
let search = "B";
let result = {};
for (let key in x) {
let tmp = {};
for (let subKey in x[key]) {
if (subKey.includes(search)) { // Use startsWithif you want even substring that aren't at the beginning
tmp[subKey] = x[key][subKey];
}
if (Object.keys(tmp).length > 0) {
result[key] = Object.assign({}, tmp);
}
}
}
console.log(result)
If you want an arbitrary deep, you should try with some kind of recursion, but that will be more complex.
Here's a solution that uses the lodash library. Lodash has a number of super useful methods for object manipulation, in this case _.pickBy and _.mapValues can be used to filter your nested object.
Example:
let x = {
"people": {
"Sally": "value",
"Bob": "other value"
},
"cars": {
"Saab": "this",
"Chevy": "that"
},
"trees": {
"Birch": "what",
"Oak": "where"
}
}
function search(query) {
query = query.toLowerCase();
const matched = _.mapValues(x, v => _.pickBy(v, (_, k) => k.toLowerCase().includes(query)));
return _.pickBy(matched, v => Object.keys(v).length)
}
console.log(search("S"))
console.log(search("b"))
console.log(search("bo"))
console.log(search("e"))
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>

How to iterate through nested objects in a generic way

I am trying to fetch the value of the nested objects without using it's key. Like for example if I have a object like
var a = {"key" : "100"}
I don't want to use a.key, to get the result, though i have nested objects, it is becoming difficult for me to fetch the value this is what I have tried:
var Obj = [{"ghi":{"content":"abc"}},{"def":{"imgURL":"test.png"}},{"abc":{"key":"001"}},{"ghi":{"content":"abc"}},{"def":{"imgURL":"test.png"}},{"abc":{"key":"001"}}]
for(var key in Obj){
abc = Obj[key]
for(var j in abc){
def = abc[key]
}
}
So i need the values of all the objects, without using the key directly.
Maybe this helps
function getValues(array, key) {
var result = [];
array.forEach(function (a) {
a[key] && result.push(a[key]);
});
return result;
}
var array = [{ "ghi": { "content": "abc" } }, { "def": { "imgURL": "test.png" } }, { "abc": { "key": "001" } }, { "ghi": { "content": "abc" } }, { "def": { "imgURL": "test.png" } }, { "abc": { "key": "001" } }];
document.write('<pre>' + JSON.stringify(getValues(array, 'ghi'), 0, 4) + '</pre>');

Categories

Resources