i am having JSON Object in the form of
{
"detailObject": {
"user": {
"userProperty": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "4 hrs"
}
},
"userRegion": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "5 hrs"
}
}
},
"OtherInfo": [
{
"year": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
},
"volume": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
}
}
]
}
}
Now i want to map it in a single object like {"userProperty":"4 hrs","userRegion":"5 hrs","year":"","volume":""} i.e parent key and duration
or [{"userProperty":"4 hrs"},{"userRegion":"5 hrs"},{"year":""},{"volume":""}]
You could do the exhausive traverse through the data object:
the base condition is to stop when a checked value is not an array and object
if the value to check is an array, continue to traverse through each element
if the value is an object, check if it contains the non-undefined path of active.duration, if the that condition is met, store the key and the value achieved from that path
const res = []
const exhausiveTraverse = (data) => {
if (isArray(data)) {
data.map((el) => exhausiveTraverse(el))
} else if (isObject(data)) {
Object.entries(data).map(([key, value]) => {
if (getByPath(value, ["active", "duration"]) !== undefined) {
res.push({ [key]: getByPath(value, ["active", "duration"]) })
} else {
exhausiveTraverse(value)
}
})
} else {
return undefined
}
}
Full code
const data = {
detailObject: {
user: {
userProperty: {
active: {
id: "3be0d467",
value: null,
duration: "4 hrs",
},
},
userRegion: {
active: {
id: "3be0d467",
value: null,
duration: "5 hrs",
},
},
},
OtherInfo: [
{
year: {
active: {
id: "3be0d467",
value: null,
duration: "",
},
},
volume: {
active: {
id: "3be0d467",
value: null,
duration: "",
},
},
},
],
},
}
const isArray = (arr) => Array.isArray(arr)
const isObject = (obj) =>
typeof obj === "object" && obj !== null && !Array.isArray(obj)
const getByPath = (obj, path) => {
try {
return path.reduce((acc, p) => acc[p], obj)
} catch (err) {
return undefined
}
}
const res = []
const exhausiveTraverse = (data) => {
if (isArray(data)) {
data.map((el) => exhausiveTraverse(el))
} else if (isObject(data)) {
Object.entries(data).map(([key, value]) => {
if (getByPath(value, ["active", "duration"]) !== undefined) {
res.push({ [key]: getByPath(value, ["active", "duration"]) })
} else {
exhausiveTraverse(value)
}
})
} else {
return undefined
}
}
exhausiveTraverse(data)
console.log(res)
You can do this by looping through the object's properties.
Note: This assumes that your object will always look the way you described it above, where:
detailObject.user is an object of sub-objects, where each sub-object has subObject.active.duration
detailObject.OtherInfo is an array of one object, where the object has object.active.duration
In this example, I use Object.entries().
const myObject = {
"detailObject": {
"user": {
"userProperty": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "4 hrs"
}
},
"userRegion": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "5 hrs"
}
}
},
"OtherInfo": [
{
"year": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
},
"volume": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
}
}
]
}
};
const results = {};
for (const [userDataName, userData] of Object.entries(myObject.detailObject.user)) {
results[userDataName] = userData.active.duration;
}
for (const [userDataName, userData] of Object.entries(myObject.detailObject.OtherInfo[0])) {
results[userDataName] = userData.active.duration;
}
console.log(JSON.stringify(results, null, '\t'));
Since the object has different types of data, they must be converted to the same type. I use flat to move the array at OtherInfo to a higher level. Then collect a new object using reduce.
const myObject = {
"detailObject": {
"user": {
"userProperty": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "4 hrs"
}
},
"userRegion": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "5 hrs"
}
}
},
"OtherInfo": [{
"year": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
},
"volume": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
}
}]
}
};
const result = Object.values(myObject.detailObject)
.flat(Infinity)
.reduce((obj, value) => (Object.entries(value).forEach(item => obj[item[0]] = item[1].active.duration), obj), {});
console.log(result);
Recursive approach will be helpful here. Use Object.entries and recursively check for "active" and "duration" keys.
const recuriveAdd = (obj, res) => {
if (Array.isArray(obj)) {
obj.forEach((item) => recuriveAdd(item, res));
} else {
Object.entries(obj).forEach(([key, value]) => {
if ("active" in value) {
res.push({ [key]: value.active.duration });
} else {
Object.values(value).forEach((item) => recuriveAdd(item, res));
}
});
}
};
obj = {
detailObject: {
user: {
userProperty: {
active: {
id: "3be0d467",
value: null,
duration: "4 hrs",
},
},
userRegion: {
active: {
id: "3be0d467",
value: null,
duration: "5 hrs",
},
},
},
OtherInfo: [
{
year: {
active: {
id: "3be0d467",
value: null,
duration: "",
},
},
volume: {
active: {
id: "3be0d467",
value: null,
duration: "",
},
},
},
],
},
};
const res = [];
recuriveAdd(obj, res);
console.log(res);
Try this out.
const jsonObj = {
"detailObject": {
"user": {
"userProperty": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "4 hrs"
}
},
"userRegion": {
"active": {
"id": "3be0d467",
"value": null,
"duration": "5 hrs"
}
}
},
"OtherInfo": [{
"year": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
},
"volume": {
"active": {
"id": "3be0d467",
"value": null,
"duration": ""
}
}
}]
}
};
const {detailObject: {user}} = jsonObj;
const {detailObject: {OtherInfo: [other]}} = jsonObj;
const customObj = {...user, ...other};
const myObj = (
({
userProperty: {active: {duration: propDur}},
userRegion: {active: {duration: regDur}},
year: {active: {duration: yearDur}},
volume: {active: {duration: volDur}}
}) => ({
userProperty: propDur,
userRegion: regDur,
year: yearDur,
volume: volDur
})
)(customObj);
console.log(myObj);
I think the best solution should be using destructuring of objects. I created myObj, the one that you need, using IIFE.
Using my approach you can also declare a default value for a key, if not found in the jsonObj.
Related
I Have Two Array, One is normal one where dates values are being stored
var = [
"2022-05-01",
"2022-05-02",
"2022-05-03",
"2022-05-04",
"2022-05-05",
"2022-05-06",
"2022-05-07",
"2022-05-08",
"2022-05-09",
"2022-05-10",
"2022-05-11",
"2022-05-12",
"2022-05-13",
"2022-05-14",
"2022-05-15",
"2022-05-16",
"2022-05-17",
"2022-05-18",
"2022-05-19",
"2022-05-20",
"2022-05-21",
"2022-05-22",
"2022-05-23",
"2022-05-24",
"2022-05-25",
"2022-05-26",
"2022-05-27",
"2022-05-28",
"2022-05-29",
"2022-05-30"
]
The other one is objects of Array where two objects are present
var b = [
{
"k_id": "6dcb67eb-1c8a-4239-9446-f9d8f6a68086",
"v_id": "aacc1765-a1d3-43c3-8233-beae19d258e5",
"key": "Testing",
"value": "999",
"start_date": "2022-05-06T00:00:00.000Z",
"end_date": "2022-05-06T00:00:00.000Z"
},
{
"k_id": "6dcb67eb-1c8a-4239-9446-f9d8f6a68086",
"v_id": "ad95cc4a-ec72-4d6e-a452-f519358f265d",
"key": "Testing",
"value": "189",
"start_date": "2022-05-08T00:00:00.000Z",
"end_date": "2022-05-`enter code here`08T00:00:00.000Z"
}
]
My Requirement is to Convert new array into like this
[
{
"value": "",
"value_id": "",
"date": "2022-05-01"
},
{
"value": "",
"value_id": "",
"date": "2022-05-02"
},
{
"value": "",
"value_id": "",
"date": "2022-05-03"
},
{
"value": "",
"value_id": "",
"date": "2022-05-04"
},
{
"value": "",
"value_id": "",
"date": "2022-05-05"
},
{
"value": "999",
"value_id": "48138929-6848-4ffe-86ce-183c75d021b4",
"date": "2022-05-06"
},
{
"value": "",
"value_id": "",
"date": "2022-05-07"
},
{
"value": "189",
"value_id": "06c4f66f-efae-4981-bebd-6734addab4a5",
"date": "2022-05-08"
},
{
"value": "",
"value_id": "",
"date": "2022-05-09"
},
{
"value": "",
"value_id": "",
"date": "2022-05-10"
},
{
"value": "",
"value_id": "",
"date": "2022-05-11"
}
]
Like in the object 2022-06-11 data is there, so the new array will consist an object which will have properties related to that object. Similar to if the object has start_date present which is also in date array, so the new array will consist object for those info. Otherwise it will create blank object respective to date.
But I am able to come with this
[
{
"value": "999",
"value_id": "aacc1765-a1d3-43c3-8233-beae19d258e5",
"date": "2022-05-06"
},
{
"value": "189",
"value_id": "ad95cc4a-ec72-4d6e-a452-f519358f265d",
"date": "2022-05-08"
},
{
"value": "",
"date": "2022-05-03"
},
{
"value": "",
"date": "2022-05-04"
},
{
"value": "",
"date": "2022-05-05"
},
{
"value": "",
"date": "2022-05-06"
},
{
"value": "",
"date": "2022-05-07"
},
{
"value": "",
"date": "2022-05-08"
},
{
"value": "",
"date": "2022-05-09"
},
{
"value": "",
"date": "2022-05-10"
},
{
"value": "",
"date": "2022-05-11"
},
{
"value": "",
"date": "2022-05-12"
},
{
"value": "",
"date": "2022-05-13"
},
{
"value": "",
"date": "2022-05-14"
},
{
"value": "",
"date": "2022-05-15"
},
{
"value": "",
"date": "2022-05-16"
},
{
"value": "",
"date": "2022-05-17"
},
{
"value": "",
"date": "2022-05-18"
},
{
"value": "",
"date": "2022-05-19"
},
{
"value": "",
"date": "2022-05-20"
},
{
"value": "",
"date": "2022-05-21"
},
{
"value": "",
"date": "2022-05-22"
},
{
"value": "",
"date": "2022-05-23"
},
{
"value": "",
"date": "2022-05-24"
},
{
"value": "",
"date": "2022-05-25"
},
{
"value": "",
"date": "2022-05-26"
},
{
"value": "",
"date": "2022-05-27"
},
{
"value": "",
"date": "2022-05-28"
},
{
"value": "",
"date": "2022-05-29"
},
{
"value": "",
"date": "2022-05-30"
}
]
It is taking only first entry and printing and rest are coming as blank.
My Code: -
var a = {};
dateArr = [];
for (var j = 0; j < this.date_val.length; j++) {
debugger;
var b = {}
console.log(val2.value[j]);
if (val2.value.length > 0) {
const newKey = this.date_val[j];
b[newKey] = val1.data;
// if (
// moment(val2.value[j].start_date).format("YYYY-MM-DD") !=
// this.date_val[j]
// ) {
// this.vala = val2.value[j].value;
// this.valb = val2.value[j].val_id;
// this.valc = moment(val2.value[j].start_date).format(
// "YYYY-MM-DD"
// );
// }
// if (
// moment(val2.value[j].start_date).format("YYYY-MM-DD") !=
// this.date_val[j]
// ) {
a = {
value:
val2.value[j] != undefined ? val2.value[j].value : "",
value_id:
val2.value[j] != undefined
? val2.value[j].v_id
: undefined,
date:
val2.value[j] != undefined
? moment(val2.value[j].start_date).format(
"YYYY-MM-DD"
)
: this.date_val[j],
};
// }
} else {
a = {
value: "",
value_id: undefined,
date: this.date_val[j],
};
}
dateArr.push(a);
}
this.nameArray.push({
key: val1.key,
key_val: val1.id,
date: dateArr,
});
Can someone please help me with this? Thanks in Advance.
var a = [
"2022-05-01",
"2022-05-02",
"2022-05-03",
"2022-05-04",
"2022-05-05",
"2022-05-06",
"2022-05-07",
"2022-05-08",
"2022-05-09",
"2022-05-10",
"2022-05-11",
"2022-05-12",
"2022-05-13",
"2022-05-14",
"2022-05-15",
"2022-05-16",
"2022-05-17",
"2022-05-18",
"2022-05-19",
"2022-05-20",
"2022-05-21",
"2022-05-22",
"2022-05-23",
"2022-05-24",
"2022-05-25",
"2022-05-26",
"2022-05-27",
"2022-05-28",
"2022-05-29",
"2022-05-30",
];
var b = [
{
k_id: "6dcb67eb-1c8a-4239-9446-f9d8f6a68086",
v_id: "aacc1765-a1d3-43c3-8233-beae19d258e5",
key: "Testing",
value: "999",
start_date: "2022-05-06T00:00:00.000Z",
end_date: "2022-05-06T00:00:00.000Z",
},
{
k_id: "6dcb67eb-1c8a-4239-9446-f9d8f6a68086",
v_id: "ad95cc4a-ec72-4d6e-a452-f519358f265d",
key: "Testing",
value: "189",
start_date: "2022-05-08T00:00:00.000Z",
end_date: "2022-05-08T00:00:00.000Z",
},
];
let results = a.map((dateString, idx) => {
// You'll want to parse the time, many ways
// to do this, then compare times. This is
// hardcoded to work for this exact format
let bWithMatchedIndices = b.find(
({ start_date }) => dateString === start_date.split("T")[0]
);
if (bWithMatchedIndices?.start_date.split("T")[0] === dateString) {
return {
date: dateString,
value: bWithMatchedIndices.value,
value_id: bWithMatchedIndices.v_id,
};
} else {
return {
date: dateString,
value: "",
value_id: "",
};
}
});
console.log(results);
Just loop over the dates in A and find a match in B. Then create an object with the members you need and push it to the resulting array.
interface NewItem {
date: string,
value: string,
value_id: string
}
function transform(a: any[], b: any[]): NewItem[] {
let newArray: NewItem[] = []
a.forEach(item => {
const objectFound = b.find(x => x.start_date.split('T')[0] === item)
if (objectFound) {
newArray.push({ date: item, value: objectFound.value, value_id: objectFound.v_id })
} else {
newArray.push({ date: item, value: '', value_id: '' })
}
})
return newArray
}
console.log(transform(a, b))
You might want to create interfaces for the two original objects too, but I think this should help you on your way just fine.
Here's the result in a Playground.
I am working on a problem where I would like to transform the following object structure:
[
{
"label": "testType",
"categories": [
{
"label": "testCatType",
"subCategories": [
{
"label": "newSubCat",
"subSubCategories": [
{
"label": "newSubSubCat1"
},
{
"label": "newSubSubCat2"
},
{
"label": "newSubSubCat3"
}
]
}
]
}
]
},
{
"label": "newType",
"categories": [
{
"label": "newCat10",
"subCategories": [
{
"label": "newCatSub1",
"subSubCategories": [
{
"label": "bingo11"
},
{
"label": "bingo12"
},
{
"label": "bingo15"
}
]
}
]
}
]
},
{
"label": "displacement",
"categories": []
},
{
"label": "brush",
"categories": [
{
"label": "blood",
"subCategories": []
},
{
"label": "damage",
"subCategories": []
},
]
}
]
into something like this:
{
"testType": {
"testCatType": {
"newSubCat": {
"newSubSubCat1": {},
"newSubSubCat2": {},
"newSubSubCat3": {}
}
}
},
"newType": {
"newCat10": {
"newCatSub1": {
"bingo11": {},
"bingo12": {},
"bingo15": {}
}
}
},
"displacement": {},
....
}
I have implemented the following recursive solution for this:
recursiveAssign(obj, json) {
if (_.isUndefined(obj)) {
return;
}
let totalKeys = _.keys(obj);
return _.assign(json, { [obj['label']]: this.test(obj[totalKeys[1]], json) })
}
transform(typeObj){
let json = {};
_.forEach(typeObj, obj => {
let totalKeys = _.keys(obj);
if (totalKeys < 2) {
_.assign(json, obj['label']);
} else {
_.assign(json, { [obj['label']]: this.recursiveAssign(obj[totalKeys[1]], json) })
}
})
}
Now the end result of this is an object that is a copy of itself on each level and I don't quite understand what the problem is. I think my approach is not faulty as I take the label and call the recursive function on the other part of that object. Can please someone point out to the potential issue!
You can write transform as a simple recursive function -
function transform (all = []) {
return Object.fromEntries(all.map(t =>
[t.label, transform(t.categories ?? t.subCategories ?? t.subSubCategories)]
))
}
const data =
[{"label":"testType","categories":[{"label":"testCatType","subCategories":[{"label":"newSubCat","subSubCategories":[{"label":"newSubSubCat1"},{"label":"newSubSubCat2"},{"label":"newSubSubCat3"}]}]}]},{"label":"newType","categories":[{"label":"newCat10","subCategories":[{"label":"newCatSub1","subSubCategories":[{"label":"bingo11"},{"label":"bingo12"},{"label":"bingo15"}]}]}]},{"label":"displacement","categories":[]},{"label":"brush","categories":[{"label":"blood","subCategories":[]},{"label":"damage","subCategories":[]},]}]
console.log(JSON.stringify(transform(data), null, 2))
{
"testType": {
"testCatType": {
"newSubCat": {
"newSubSubCat1": {},
"newSubSubCat2": {},
"newSubSubCat3": {}
}
}
},
"newType": {
"newCat10": {
"newCatSub1": {
"bingo11": {},
"bingo12": {},
"bingo15": {}
}
}
},
"displacement": {},
"brush": {
"blood": {},
"damage": {}
}
}
You can chain ... ?? t.subSubSubCategories and ... ?? t.subSubSubSubCategories, if needed. A better approach would be to create a consistent node interface for all nodes in your graph. You could achieve this by renaming all sub*Categories to simply categories. This will give each node an inteface like
Node: { label: String, categories: Array<Node> }
You can solve this in pure js like this:
const arr = [{ "label": "testType", "categories": [{ "label": "testCatType", "subCategories": [{ "label": "newSubCat", "subSubCategories": [{ "label": "newSubSubCat1" }, { "label": "newSubSubCat2" }, { "label": "newSubSubCat3" }] }] }] }, { "label": "newType", "categories": [{ "label": "newCat10", "subCategories": [{ "label": "newCatSub1", "subSubCategories": [{ "label": "bingo11" }, { "label": "bingo12" }, { "label": "bingo15" }] }] }] }, { "label": "displacement", "categories": [] }, { "label": "brush", "categories": [{ "label": "blood", "subCategories": [] }, { "label": "damage", "subCategories": [] }, ] }];
let result = recursive(arr);
console.log(result);
function recursive(arr) {
let result = {};
let returnValue = {}
for (let obj of arr) {
let entries = Object.entries(obj);
if (!entries.length) {
return {};
}
for (let [key, value] of entries) {
if (typeof value == "object") {
result = recursive(value);
}
}
const label = obj["label"];
returnValue = { ...returnValue,
[obj["label"]]: result
};
}
return returnValue;
}
.as-console-wrapper {min-height: 100%;}
I filtering group of object like this:
[
{
"Username":"00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes":[
{
"Name":"custom:organization",
"Value":"zxc"
},
{
"Name":"sub",
"Value":"00d9a7f4-0f0b-448b-91fc-fa5aef314d06"
},
{
"Name":"email_verified",
"Value":"false"
},
{
"Name":"email",
"Value":"zigor#freeallapp.com"
}
],
"UserCreateDate":"2021-02-04T17:59:28.212Z",
"UserLastModifiedDate":"2021-02-04T17:59:28.212Z",
"Enabled":true,
"UserStatus":"UNCONFIRMED"
},
{
"Username":"07c16a30-b994-4267-9794-6fb20739abeb",
"Attributes":[
{
"Name":"custom:organization",
"Value":"asd"
},
{
"Name":"sub",
"Value":"07c16a30-b994-4267-9794-6fb20739abeb"
},
{
"Name":"email_verified",
"Value":"false"
},
{
"Name":"email",
"Value":"2marwan.khatar.39#dankq.com"
}
],
"UserCreateDate":"2021-02-04T17:56:13.787Z",
"UserLastModifiedDate":"2021-02-04T17:56:13.787Z",
"Enabled":true,
"UserStatus":"UNCONFIRMED"
},
Following is filtering fine
let filterarry;
filterarry = jsonObject.filter(Attributes => {
return Attributes.Enabled == true && Attributes.UserStatus == 'UNCONFIRMED';
});
console.log(filterarry);
I am trying to filter by Attributes having:
Attributes that have custom:organization and with value zxc
how can I do that ??
"Attributes":[
{
"Name":"custom:organization",
"Value":"zxc"
},
I tried few methods but i am getting empty array in output
Thanks
You can do this:
let output = jsonObject.filter(entry => {
// filter the internal array and check
if (entry.Attributes.filter(attr => attr.Name === 'custom:organization' && attr.Value === 'zxc').length !== 0) {
return true;
}
return false;
});
See also: https://stackoverflow.com/a/8217584/14133230
To filter jsonObject.Attributes you need to recreate and the variable
let filterarry = jsonObject.filter(item => {
item.Attributes = item.Attributes.filter(attr => {
return attr.Name == "custom:organization" && attr.Value == "zxc"
})
// return true => to remove only value of jsonObject.Attributes but not the parent
return item.Attributes.length;
});
results
[
{
"Username": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes": [
{
"Name": "custom:organization",
"Value": "zxc"
}
],
"UserCreateDate": "2021-02-04T17:59:28.212Z",
"UserLastModifiedDate": "2021-02-04T17:59:28.212Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
}
]
you can try this
const oObjects = [{
"Username": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06",
"Attributes": [{
"Name": "custom:organization",
"Value": "zxc"
},
{
"Name": "sub",
"Value": "00d9a7f4-0f0b-448b-91fc-fa5aef314d06"
},
{
"Name": "email_verified",
"Value": "false"
},
{
"Name": "email",
"Value": "zigor#freeallapp.com"
}
],
"UserCreateDate": "2021-02-04T17:59:28.212Z",
"UserLastModifiedDate": "2021-02-04T17:59:28.212Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
},
{
"Username": "07c16a30-b994-4267-9794-6fb20739abeb",
"Attributes": [{
"Name": "custom:organization",
"Value": "asd"
},
{
"Name": "sub",
"Value": "07c16a30-b994-4267-9794-6fb20739abeb"
},
{
"Name": "email_verified",
"Value": "false"
},
{
"Name": "email",
"Value": "2marwan.khatar.39#dankq.com"
}
],
"UserCreateDate": "2021-02-04T17:56:13.787Z",
"UserLastModifiedDate": "2021-02-04T17:56:13.787Z",
"Enabled": true,
"UserStatus": "UNCONFIRMED"
},
];
const filterarry = oObjects.filter(attr => {
return attr.Enabled &&
attr.UserStatus === 'UNCONFIRMED' &&
attr.Attributes.some(p => p.Name === "custom:organization" && p.Value === "zxc");
});
console.log(filterarry);
I have below this nested object
I need to create an array using this object containing keys. And if keys are object then it should use .dot syntax. and if it is an array then it should give me key.0.keyName. Is it possible to do so?
Output
[
"AllowIPNPayment",
"AllowOnlinePayment",
"MetaData.CreateTime",
"MetaData.LastUpdatedTime",
"CustomField.0.DefinitionId",
"CustomField.0.Name",
"CustomField.0.Type",
...
]
What I have tried is just ugly and does give me expected result. If it is possible with more concise way.
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
let object = {}
for (let k in invoiceObject) {
if (typeof invoiceObject[k] === "object") {
object[k] = {};
for (let l in invoiceObject[k]) {
object[k][l] = "";
}
} else if (typeof invoiceObject[k] === "array") {
object[k] = [];
for (let l in invoiceObject[k][0]) {
object[k][l] = "";
}
} else {
object[k] = "";
}
}
console.log(object)
You can create a recursive function (getSchema) that checks if a value (val) is an object (arrays included), iterate it with _.flatMap(), and collects the keys until it hits a value which is not an object. It then joins the collected keys and returns the string.
const getSchema = (val, keys = []) =>
_.isObject(val) ? // if it's an object or array
_.flatMap(val, (v, k) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Without lodash, the main change is to use Object.entries() to get an array of [key, value] pairs, since Array.flatMap() can't iterate objects:
const getSchema = (val, keys = []) =>
typeof val === 'object' && val !== null ? // if it's an object or array
Object.entries(val) // get [key, value] pairs of object/array
.flatMap(([k, v]) => getSchema(v, [...keys, k])) // iterate it and call fn with the value and the collected keys
:
keys.join('.') // return the joined keys
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 }
const result = getSchema(invoiceObject)
console.log(result)
inspired by the answer given in this post and understanding you just want to get the property-names, not values, you could do it like this. sorry, this uses plain javascript.
function flattenObjectToKeyArray(ob) {
var toReturn = [];
for (var prop in ob) {
if (!ob.hasOwnProperty(prop)) continue;
if ((typeof ob[prop]) == 'object' && ob[prop] !== null) {
var flatObject = flattenObjectToKeyArray(ob[prop]);
for (var idx = 0; idx < flatObject.length; idx++) {
toReturn.push(prop + '.' + flatObject[idx]);
}
} else {
toReturn.push(prop);
}
}
return toReturn;
}
You could solve this with a recursive function. The function below keeps track of the current keys, and joins them as soon as an end point is reached (a non-object or empty object/array).
const invoiceObject = { "AllowIPNPayment": false, "AllowOnlinePayment": false, "AllowOnlineCreditCardPayment": false, "AllowOnlineACHPayment": false, "domain": "QBO", "sparse": false, "Id": "16", "SyncToken": "1", "MetaData": { "CreateTime": "2020-03-25T15:10:40-07:00", "LastUpdatedTime": "2020-03-26T11:06:49-07:00" }, "CustomField": [{ "DefinitionId": "1", "Name": "Crew #", "Type": "StringType" }], "DocNumber": "1007", "TxnDate": "2020-03-03", "CurrencyRef": { "value": "USD", "name": "United States Dollar" }, "LinkedTxn": [{ "TxnId": "32", "TxnType": "Payment" }], "Line": [{ "Id": "1", "LineNum": 1, "Description": "Custom Design", "Amount": 750, "DetailType": "SalesItemLineDetail", "SalesItemLineDetail": { "ItemRef": { "value": "4", "name": "Design" }, "UnitPrice": 75, "Qty": 10, "TaxCodeRef": { "value": "NON" } } }, { "Amount": 750, "DetailType": "SubTotalLineDetail", "SubTotalLineDetail": {} } ], "TxnTaxDetail": { "TotalTax": 0 }, "CustomerRef": { "value": "13", "name": "uiool" }, "CustomerMemo": { "value": "Thank you for your business and have a great day!" }, "SalesTermRef": { "value": "3" }, "DueDate": "2020-04-02", "TotalAmt": 750, "ApplyTaxAfterDiscount": false, "PrintStatus": "NeedToPrint", "EmailStatus": "NotSet", "BillEmail": { "Address": "uiikoool" }, "Balance": 450 };
function getDotKeys(item, keys = []) {
const isObject = item && typeof item == "object";
if (!isObject) return Array.of(keys.join("."));
const pairs = Array.isArray(item)
? item.map((value, index) => [index, value])
: Object.entries(item);
const isEmpty = !pairs.length;
if (isEmpty) return Array.of(keys.join("."));
const result = [];
for (const [key, value] of pairs) {
const dotKeys = getDotKeys(value, [...keys, key]);
result.push(...dotKeys);
}
return result;
}
console.log(getDotKeys(invoiceObject));
This does produce a different result than what you have in your question, since your solution stops at the second level for objects and third level for arrays. This solution also includes more then only index 0.
I have a few empty objects in my JSON request:
FXP:
"createdBy": {},
I would like to before the request is sent to the server convert these empty objects into following structure:
"createdBy": null,
How can I do it recursively in whole object please?
Example:
{
"main": {
"id": null,
"archived": true,
"createdBy": {},
"creationTime": null,
"location": {
"id": 79,
"address": {
"id": 79,
"city": null,
"latitude": 50.072613888888895,
"longitude": 14.543111111111111,
"street": null,
"streetNumber": null,
"district": null
},
"bsc": "BSC123",
"code": null,
"indoorOutdoor": null,
"siteId": "A0RST",
"stationType": {
"id": 1,
"name": "Indoor solution"
},
"shared": false,
"sapSacIrnCode": "31049.0",
"abloyLocation": "NA",
"name": "A0RST"
},
"actionName": {},
"orderType": {},
"project": {
"id": 1,
"cards": [],
"color": null,
"managerCustomer": null,
"managerSuntel": null,
"heliosSync": false,
"name": "Vodafone Test",
"parentProject": null,
"team": null,
"facility": {
"id": 1,
"code": 110,
"name": "110_MANAGEMENT"
},
"workers": []
},
"note": "",
"orderNumber": "2626262"
},
"milestoneSequence": {},
"milestones": []
}
In JSON.parse resp. JSON.stringify you can pass a function as the 2nd argument.
This function gets name and value as arguments.
So you can adjust the values during parsing resp. stringifying.
Here is a recursive function that might help you:
function nullify (obj) {
for(key in obj) {
if(JSON.stringify(obj[key])=="{}") {
obj[key] = null;
} else if (typeof obj[key] == "object" && !Date.parse(obj[key])) {
obj[key] = nullify(obj[key]);
}
}
return obj;
}
for this example :
var obj = {
"b": 1,
"c": {},
"d": {
"a": 1,
"b": {},
"c": {
"x": 1,
"y": {}
}
}
}
the result of nullify(obj); is
{
"b": 1,
"c": null,
"d": {
"a": 1,
"b": null,
"c": {
"x": 1,
"y": null
}
}
}
If you don't like using strings too much:
function emptyObjToNull(object){
var isObject, hasKeys, isArray, current;
for(var k in object){
if(!object.hasOwnProperty(k))
return;
current = object[k];
isObject = typeof current == 'object';
hasKeys = isObject && Object.keys(current).length !== 0;
isArray = isObject && Object.prototype.toString.call(current) === "[object Array]";
if(hasKeys){
emptyObjToNull(current);
}else if(isArray){
for(var i = current.length; i--;){
emptyObjToNull(current);
}
}else if(isObject && !hasKeys){
object[k] = null; // Set the key directly, not the reference
}
}
}
Fiddle: http://jsfiddle.net/cfvm3r63/3/
Here is a solution using object-scan. Depending on your scenario using a dependency might make sense
// const objectScan = require('object-scan');
const data = {"main":{"id":null,"archived":true,"createdBy":{},"creationTime":null,"location":{"id":79,"address":{"id":79,"city":null,"latitude":50.072613888888895,"longitude":14.543111111111111,"street":null,"streetNumber":null,"district":null},"bsc":"BSC123","code":null,"indoorOutdoor":null,"siteId":"A0RST","stationType":{"id":1,"name":"Indoor solution"},"shared":false,"sapSacIrnCode":"31049.0","abloyLocation":"NA","name":"A0RST"},"actionName":{},"orderType":{},"project":{"id":1,"cards":[],"color":null,"managerCustomer":null,"managerSuntel":null,"heliosSync":false,"name":"Vodafone Test","parentProject":null,"team":null,"facility":{"id":1,"code":110,"name":"110_MANAGEMENT"},"workers":[]},"note":"","orderNumber":"2626262"},"milestoneSequence":{},"milestones":[]};
const nullify = (input) => objectScan(['**'], {
rtn: 'count',
filterFn: ({ value, parent, property }) => {
if (
value instanceof Object
&& !Array.isArray(value)
&& Object.keys(value).length === 0
) {
parent[property] = null;
return true;
}
return false;
}
})(input);
console.log(nullify(data)); // returns number of changes
// => 4
console.log(data);
// => { main: { id: null, archived: true, createdBy: null, creationTime: null, location: { id: 79, address: { id: 79, city: null, latitude: 50.072613888888895, longitude: 14.543111111111111, street: null, streetNumber: null, district: null }, bsc: 'BSC123', code: null, indoorOutdoor: null, siteId: 'A0RST', stationType: { id: 1, name: 'Indoor solution' }, shared: false, sapSacIrnCode: '31049.0', abloyLocation: 'NA', name: 'A0RST' }, actionName: null, orderType: null, project: { id: 1, cards: [], color: null, managerCustomer: null, managerSuntel: null, heliosSync: false, name: 'Vodafone Test', parentProject: null, team: null, facility: { id: 1, code: 110, name: '110_MANAGEMENT' }, workers: [] }, note: '', orderNumber: '2626262' }, milestoneSequence: null, milestones: [] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan