let data = [{
system: {
id: "4gSSbjCFEorYXqrgDIP2FA",
type: "Entry",
name: "User"
},
DataDetails: {
shortOption: {
"en-us": "some value"
},
mediaFile: [{
sys: {
type: "Link",
link: "Entry",
id: "7kRzyt4PFo",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "2OspeCtNK0s",
},
},
],
mediaGalary: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
],
mediaExplore: [{
sys: {
type: "Link",
link: "Asset",
id: "euwcbds3282",
},
},
{
sys: {
type: "Link",
linkType: "Asset",
id: "jndsiw23912",
},
},
],
singleMediaImage: {
sys: {
type: "Link",
linkType: "Asset",
id: "7kRzyt4PFo",
},
},
},
},
{
system: {
id: "1aBOO8tu3lUsjtICuIbUM5",
type: "Entry",
name: "User"
},
DataDetails: {
short: {
"en-us": "details of shorts"
},
shortSlugOption: {
"hi-In": "options"
},
booleanField: {
kl: "true"
},
},
},
{
system: {
id: "2pOUGnI1oRD7nsrYs600HA",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: [{
sys: {
type: "Link",
link: "Entry",
id: "66rzYr2BpWL",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "1VTBHdLTdSW",
},
},
],
},
},
{
system: {
id: "66rzYr2BpWL1VTBHdLTdSW",
type: "Entry",
name: "new"
},
DataDetails: {
oneReference: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
multiReference: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
link: "Asset",
id: "h2cPiuU9jIz",
},
},
],
},
},
{
system: {
id: "cIb5mqEBRWDD6hrNmFmFE",
type: "Entry",
name: "new"
},
DataDetails: {
testingNewValue: {
"hi-IN": "jksdsdo"
}
},
},
{
system: {
id: "7kRzyt4PFrX13gHcw3Z1Ko",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: {
"en-us": "kknksdo"
}
},
},
];
let anotherObj = {
"gHcw3Z1Ko": {
status: true,
tag: [],
filename: "exute-image.jpg",
is_dir: false,
parent_uid: null,
},
"h2cPiuU9jIz": {
status: true,
tag: [],
filename: "wallpapers-6.jpg",
is_dir: false,
parent_uid: null,
},
"7kRzyt4PFo": {
status: true,
tag: [],
filename: "in-space-rk.jpg",
is_dir: false,
parent_uid: null,
},
"euwcbds3282": {
status: true,
tag: [],
filename: "justice-league.jpg",
is_dir: false,
parent_uid: null,
},
"jndsiw23912": {
status: true,
tag: [],
filename: "batman.jpg",
is_dir: false,
parent_uid: null,
},
};
let res = data.reduce((acc, curr) => {
if (!acc[curr.system.name]) {
acc[curr.system.name] = {};
}
let detailsObj = {};
let assetArray=[];
for (let key of Object.keys(curr.DataDetails)) {
detailsObj[key] = Object.values(curr.DataDetails[key])[0];
if (typeof Object.values(curr.DataDetails[key])[0] === "object") {
Object.values(curr.DataDetails[key]).map((type) => {
if (Array.isArray(type)) {
type.map((link) => {
if (link.sys.link === "Asset") {
for (let id in anotherObj) {
if (link.sys.id === id) {
assetArray.push(anotherObj[id]);
detailsObj[key] = assetArray;
}
}
}
});
} else {
if (type.sys !== undefined) {
// for single Asset
if (type.sys.link === "Asset") {
for (let id in anotherObj) {
if (type.sys.id === id) {
detailsObj[key] = [anotherObj[id]];
}
}
}
}
}
});
}
}
acc[curr.system.name][curr.system.id] = {
title: curr.system.id,
uid: curr.system.id,
url: `/${curr.system.name}/${curr.system.id}`,
...detailsObj,
};
return acc;
}, {});
console.log(res);
I am trying to put two object data in one output but by reading the link which is Asset
but in the multiple Array list the output is displaying as single Asset output as mediaFile
contain two entries but I don't know where I am doing wrong and it's displaying me a single value
as my main purpose is to replace the sys:{id:erfrdvsdf}
by the anotherObj key data
so it should look like this for example my output is like this
"User": {
"4gSSbjCFEorYXqrgDIP2FA": {
"title": "4gSSbjCFEorYXqrgDIP2FA",
"uid": "4gSSbjCFEorYXqrgDIP2FA",
"url": "/User/4gSSbjCFEorYXqrgDIP2FA",
"shortOption": "some value",
"mediaFile": {
"sys": {
"type": "Link",
"link": "Entry",
"id": "7kRzyt4PFo"
}
},
"mediaGalary": [
{
/**id:7**/
"status": true,
"tag": [],
"filename": "in-space-rk.jpg",
"is_dir": false,
"parent_uid": null
}
],
"singleMediaImage": {
"type": "Link",
"linkType": "Asset",
"id": "h2cPiuU9jIz"
}
},
},
but it should like this
"User": {
"4gSSbjCFEorYXqrgDIP2FA": {
"title": "4gSSbjCFEorYXqrgDIP2FA",
"uid": "4gSSbjCFEorYXqrgDIP2FA",
"url": "/User/4gSSbjCFEorYXqrgDIP2FA",
"shortOption": "some value",
"mediaFile": {
"sys": {
"type": "Link",
"link": "Entry",
"id": "7kRzyt4PFo"
}
},
"mediaGalary": [
{
"status": true,
"tag": [],
"filename": "in-space-rk.jpg",
"is_dir": false,
"parent_uid": null
},
{
"status": true,
"tag": [],
"filename": "wallpapers-6.jpg",
"is_dir": false,
"parent_uid": null
},
],
"mediaExplore": [
{
"status": true,
"tag": [],
"filename": "justice-league",
"is_dir": false,
"parent_uid": null
},
{
"status": true,
"tag": [],
"filename": "batman.jpg",
"is_dir": false,
"parent_uid": null
},
],
"singleMediaImage": [
{
"status": true,
"tag": [],
"filename": "wallpapers-6.jpg",
"is_dir": false,
"parent_uid": null
},
]
},
},
but my expected output is what I am looking to it
Due to this I am stuck with the entry field as the same problem I am going through with entry field as I wrote same code to fetch the entry fields which are in Array and for the single entry field
where my code break I don't know
I know this is long code but help me out to solve this error as due to this I am not moving ahead
CodePudding user response:
You are missing some values because you don't check for linkType
.
Your loops are checking for sys.link
but aren't checking for sys.linkType
.
Use:
link.sys.link === 'Asset' || link.sys.linkType === 'Asset'
and
type.sys.link === 'Asset' || type.sys.linkType === 'Asset'
Also this line will override your array: detailsObj[key] = [anotherObj[id]];
Replace it with:
assetArray.push(anotherObj[id]);
detailsObj[key] = assetArray;
To be clear this code isn't good. A few suggestions:
- Split your code in smaller logic units. Don't nest 5 levels of loops. Make functions that do small operations and name them accordingly (e.g. instead of doing
for (let id in anotherObj) { ... }
, put the logic inside a function namedfindAssetData
) - Understand the difference between
Array.prototype.forEach
andArray.prototype.map
(map usage in this code is wrong) - Use code quality tools like eslint, it will help if you are a beginner
CodePudding user response:
There's an error in your code: anotherObj
has duplicate keys. If you log that out, you'll see that there are only two entries in that object:
let anotherObj = {
gHcw3Z1Ko: {
status: true,
tag: [],
filename: "exute-image.jpg",
is_dir: false,
parent_uid: null,
},
h2cPiuU9jIz: {
status: true,
tag: [],
filename: "wallpapers-6.jpg",
is_dir: false,
parent_uid: null,
},
gHcw3Z1Ko: {
status: true,
tag: [],
filename: "in-space-rk.jpg",
is_dir: false,
parent_uid: null,
},
};
console.log(anotherObj)
Also, the mediaFile
squashes the array of entries to one - you did not describe what you want to do with it, so I assumed that the first item from the array suffices.
But probably this is not what you are after (in the following snippet, I removed the first entry of the duplicate keys):
let data = [{
system: {
id: "4gSSbjCFEorYXqrgDIP2FA",
type: "Entry",
name: "User"
},
DataDetails: {
shortOption: {
"en-us": "some value"
},
mediaFile: [{
sys: {
type: "Link",
link: "Entry",
id: "7kRzyt4PFo",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "2OspeCtNK0s",
},
},
],
mediaGalary: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
],
singleMediaImage: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
},
},
{
system: {
id: "1aBOO8tu3lUsjtICuIbUM5",
type: "Entry",
name: "User"
},
DataDetails: {
short: {
"en-us": "details of shorts"
},
shortSlugOption: {
"hi-In": "options"
},
booleanField: {
kl: "true"
},
},
},
{
system: {
id: "2pOUGnI1oRD7nsrYs600HA",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: [{
sys: {
type: "Link",
link: "Entry",
id: "66rzYr2BpWL",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "1VTBHdLTdSW",
},
},
],
},
},
{
system: {
id: "66rzYr2BpWL1VTBHdLTdSW",
type: "Entry",
name: "new"
},
DataDetails: {
oneReference: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
multiReference: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
link: "Asset",
id: "h2cPiuU9jIz",
},
},
],
},
},
{
system: {
id: "cIb5mqEBRWDD6hrNmFmFE",
type: "Entry",
name: "new"
},
DataDetails: {
testingNewValue: {
"hi-IN": "jksdsdo"
}
},
},
{
system: {
id: "7kRzyt4PFrX13gHcw3Z1Ko",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: {
"en-us": "kknksdo"
}
},
},
];
let anotherObj = {
h2cPiuU9jIz: {
status: true,
tag: [],
filename: "wallpapers-6.jpg",
is_dir: false,
parent_uid: null,
},
gHcw3Z1Ko: {
status: true,
tag: [],
filename: "in-space-rk.jpg",
is_dir: false,
parent_uid: null,
},
};
// this is the function that actually merges the source
// object with anotherObj
const mergeGallery = (src, other) => {
return src.reduce((a, c) => {
if (typeof a[c.sys.id] === "undefined") a[c.sys.id] = {}
a[c.sys.id] = { ...other[c.sys.id] }
return a
}, {})
}
// just to display that the generation of conditional attributes
// can be extracted to their own functions
const getShortOption = (el) => {
const shortOption = el.system.name === "User" && el.DataDetails && el.DataDetails.shortOption ? {
shortOption: el.DataDetails.shortOption["en-us"]
} : {}
return shortOption
}
const getFormatted = (el, otherGallery) => {
return {
title: el.system.id,
uid: el.system.id,
url: `/${el.system.name}/${el.system.id}`,
...getShortOption(el),
...(el.DataDetails && el.DataDetails.mediaFile && {
mediaFile: el.DataDetails.mediaFile[0]
}),
...(el.DataDetails && el.DataDetails.mediaGalary && {
mediaGalary: mergeGallery(el.DataDetails.mediaGalary, otherGallery)
}),
...(el.DataDetails && el.DataDetails.singleMediaImage && {
singleMediaImage: el.DataDetails.singleMediaImage.sys
}),
}
}
const categorizeItems = (data) => {
return data.reduce((a, c) => {
if (typeof a[c.system.name] === "undefined") a[c.system.name] = {}
a[c.system.name][c.system.id] = getFormatted(c, anotherObj)
return a
}, {})
}
const ret = categorizeItems(data)
console.log(ret)
SUGGESTION
- The conditionals can be much shorter:
const getShortOption = (el) => {
const shortOption =
el.system.name === "User" && el.DataDetails && el.DataDetails.shortOption
? { shortOption: el.DataDetails.shortOption["en-us"], }
: {};
return shortOption;
};
// could be written as
const getShortOption = (el) => {
const shortOption = el.system.name === "User" && el.DataDetails?.shortOption?.["en-us"]
? { shortOption: el.DataDetails.shortOption["en-us"] }
: {}
return shortOption
}
If you use ?.
chaining, all the conditinals are shorter - unfortunately SO snippets do not know about this syntax.
- Please, if you use English terms in your code, then correct the spelling of
Galary
toGallery
. It will be a nice source of confusion, if you don't.
CodePudding user response:
If you traverse complex objects manually, things will get complex very fast. And it'll be nightmare to maintain the code. There are good opensource libraries available to travers complex objects using simple queries. For example, JsonPath.
In following demo I've used JsonPath. It handles Asset
as well as Entry
without any special handling. For the demo I've provided replacements for all the ids.
let data = getData();
let anotherObj = getAnotherObj();
let res = data.reduce((acc, curr) => {
if (!acc[curr.system.name]) {
acc[curr.system.name] = {};
}
let detailsObj = {};
Object.keys(curr.DataDetails).forEach(key => {
let values = curr.DataDetails[key];
// clone values to output
detailsObj[key] = !Array.isArray(values) ? Object.assign({}, values) : [...values];
// find and replace ids
let ids = jsonpath.query(detailsObj[key], '$..id');
ids.forEach((id, i) => {
if (id in anotherObj) {
if (Array.isArray(detailsObj[key]))
detailsObj[key].splice(i, 1, anotherObj[id]);
else
detailsObj[key] = anotherObj[id];
}
});
});
acc[curr.system.name][curr.system.id] = {
title: curr.system.id,
uid: curr.system.id,
url: `/${curr.system.name}/${curr.system.id}`,
...detailsObj,
};
return acc;
}, {});
document.body.insertAdjacentHTML('beforeend', `<pre>${JSON.stringify(res, undefined, 1)}</pre>`);
console.log(res);
function getData() {
return [{
system: {
id: "4gSSbjCFEorYXqrgDIP2FA",
type: "Entry",
name: "User"
},
DataDetails: {
shortOption: {
"en-us": "some value"
},
mediaFile: [{
sys: {
type: "Link",
link: "Entry",
id: "7kRzyt4PFo",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "2OspeCtNK0s",
},
},
],
mediaGalary: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
],
singleMediaImage: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
},
},
{
system: {
id: "1aBOO8tu3lUsjtICuIbUM5",
type: "Entry",
name: "User"
},
DataDetails: {
short: {
"en-us": "details of shorts"
},
shortSlugOption: {
"hi-In": "options"
},
booleanField: {
kl: "true"
},
},
},
{
system: {
id: "2pOUGnI1oRD7nsrYs600HA",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: [{
sys: {
type: "Link",
link: "Entry",
id: "66rzYr2BpWL",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "1VTBHdLTdSW",
},
},
],
},
},
{
system: {
id: "66rzYr2BpWL1VTBHdLTdSW",
type: "Entry",
name: "new"
},
DataDetails: {
oneReference: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
multiReference: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
link: "Asset",
id: "h2cPiuU9jIz",
},
},
],
},
},
{
system: {
id: "cIb5mqEBRWDD6hrNmFmFE",
type: "Entry",
name: "new"
},
DataDetails: {
testingNewValue: {
"hi-IN": "jksdsdo"
}
},
},
{
system: {
id: "7kRzyt4PFrX13gHcw3Z1Ko",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: {
"en-us": "kknksdo"
}
},
}
];
}
function getAnotherObj() {
return {
"h2cPiuU9jIz": {
status: true,
tag: [],
filename: "wallpapers-6.jpg",
is_dir: false,
parent_uid: null,
},
"gHcw3Z1Ko": {
status: true,
tag: [],
filename: "in-space-rk.jpg",
is_dir: false,
parent_uid: null,
},
"7kRzyt4PFo": {
status: true,
tag: [],
filename: "mediaFile0.jpg",
is_dir: false,
parent_uid: null,
},
"2OspeCtNK0s": {
status: true,
tag: [],
filename: "mediaFile1.jpg",
is_dir: false,
parent_uid: null,
},
"66rzYr2BpWL": {
type: 'entry',
tag: [],
entry_details: "this is first entry ***",
is_secret: false,
},
"1VTBHdLTdSW": {
type: 'entry',
tag: [],
entry_details: "some other entry ***",
is_secret: true,
},
};
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/jsonpath.min.js"></script>
Note, I haven't handled case "shortOption": "some value"
. Flattening single value objects is not in focus here anyway.
Or you can replace all the assets and entries in original object with single statement!
let data = getData();
let anotherObj = getAnotherObj();
jsonpath.apply(data, '$[*].DataDetails..[?(@.sys.id)]', e => anotherObj[e.sys.id]);
document.body.insertAdjacentHTML('beforeend', `<pre>${JSON.stringify(data, undefined, 1)}</pre>`);
console.log(data);
function getData() {
return [{
system: {
id: "4gSSbjCFEorYXqrgDIP2FA",
type: "Entry",
name: "User"
},
DataDetails: {
shortOption: {
"en-us": "some value"
},
mediaFile: [{
sys: {
type: "Link",
link: "Entry",
id: "7kRzyt4PFo",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "2OspeCtNK0s",
},
},
],
mediaGalary: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
],
singleMediaImage: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
},
},
{
system: {
id: "1aBOO8tu3lUsjtICuIbUM5",
type: "Entry",
name: "User"
},
DataDetails: {
short: {
"en-us": "details of shorts"
},
shortSlugOption: {
"hi-In": "options"
},
booleanField: {
kl: "true"
},
},
},
{
system: {
id: "2pOUGnI1oRD7nsrYs600HA",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: [{
sys: {
type: "Link",
link: "Entry",
id: "66rzYr2BpWL",
},
},
{
sys: {
type: "Link",
link: "Entry",
id: "1VTBHdLTdSW",
},
},
],
},
},
{
system: {
id: "66rzYr2BpWL1VTBHdLTdSW",
type: "Entry",
name: "new"
},
DataDetails: {
oneReference: {
sys: {
type: "Link",
linkType: "Asset",
id: "h2cPiuU9jIz",
},
},
multiReference: [{
sys: {
type: "Link",
link: "Asset",
id: "gHcw3Z1Ko",
},
},
{
sys: {
type: "Link",
link: "Asset",
id: "h2cPiuU9jIz",
},
},
],
},
},
{
system: {
id: "cIb5mqEBRWDD6hrNmFmFE",
type: "Entry",
name: "new"
},
DataDetails: {
testingNewValue: {
"hi-IN": "jksdsdo"
}
},
},
{
system: {
id: "7kRzyt4PFrX13gHcw3Z1Ko",
type: "Entry",
name: "Dummy"
},
DataDetails: {
testingNewValue: {
"en-us": "kknksdo"
}
},
}
];
}
function getAnotherObj() {
return {
"h2cPiuU9jIz": {
status: true,
tag: [],
filename: "wallpapers-6.jpg",
is_dir: false,
parent_uid: null,
},
"gHcw3Z1Ko": {
status: true,
tag: [],
filename: "in-space-rk.jpg",
is_dir: false,
parent_uid: null,
},
"7kRzyt4PFo": {
status: true,
tag: [],
filename: "mediaFile0.jpg",
is_dir: false,
parent_uid: null,
},
"2OspeCtNK0s": {
status: true,
tag: [],
filename: "mediaFile1.jpg",
is_dir: false,
parent_uid: null,
},
"66rzYr2BpWL": {
type: 'entry',
tag: [],
entry_details: "this is first entry ****",
is_secret: false,
},
"1VTBHdLTdSW": {
type: 'entry',
tag: [],
entry_details: "some other entry ****",
is_secret: true,
},
};
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/jsonpath.min.js"></script>