Home > Mobile >  JS: append array of objects with data from another
JS: append array of objects with data from another

Time:05-15

I've got some JS data holding all kinds of data, numbers, child objects, arrays, etc in all manner of different structures:

let datapile = {
  cover_img: { uid:'u2a3j4' },
  avatar_img: { uid:'u5j3vg' },
  created: 8273736384,
  friends: [
    { name:'John', img: { uid:'u2726b' }, },
    { name:'Jane', parent: { profile_img: { uid:'u293k4' }, } },
  ],
  occupation: {
    past: current,
    prior: {
      title: 'Accountant',
      company: {
        logo: { img: { uid:'u29374' } },
      }
    },
  },
  ...
}

And then I've got this JS list of images:

let imgs : [
  { uid:'u2a3j4', format:'jpg', alt_txt:'Lorem...', size:583729, dominant_color:'#d79273' },
  { uid:'u5j3vg', format:'png', alt_txt:'Lorem...', size:284849, dominant_color:'#f99383' },
  { uid:'u2726b', format:'gif', alt_txt:'Lorem...', size:293742, dominant_color:'#349a83' },
  ...
],

Now, what I need is a function I can call that will look through the datapile and append img data objects from the imgs list below. So where the datapile now has only the uid reference, it should have the entire img object. And I will then do the same with all kinds of other pieces of referenced data.

I've tried the following function:

function isArray(x){ return ( x !== undefined && Array.isArray(x) ) }
function isObject(x){ return (x && typeof x === "object" && !Array.isArray(x)) }
function get_item(type, uid) { /* loops through eg. imgs and returns img matching uid */ }

function append_referenced_relations(data){
    if( !data ) return data

    if( isObject(data) && data['uid'] !== undefined ) {
        let item = get_item('any', data['uid'])
        data = item
    }

    if( isObject(data) || isArray(data) ) {
        for( let key in data ) {
            data[key] = this.append_referenced_relations(deepClone(data[key]))
        }
    }

    return data
}

... but I just can't get it to work. And my best googling efforts for similar scenarios have also come up empty. Can the internet help me out here?

CodePudding user response:

you can try something like this

basically it use recursion and Object.fromEntries /entries to check all the keys of the inner object

if you have any specific question feel free to ask me

const decorate = (obj, data) => {

  if (typeof obj !== 'object') {
    return obj
  }
  if (Array.isArray(obj)) {
    return obj.map(e => decorate(e, data))
  }


  return Object.fromEntries(
    Object.entries(obj).flatMap(([k, v]) => {

      if (k === 'uid') {
        const imgData = data.find(d => v === d.uid)
        return Object.entries(imgData || [[k, v]])
      }

      return [
        [k, decorate(v, data)]
      ]
    })
  )
}



let datapile = {
  cover_img: {
    uid: 'u2a3j4'
  },
  avatar_img: {
    uid: 'u5j3vg'
  },
  created: 8273736384,
  friends: [{
      name: 'John',
      img: {
        uid: 'u2726b'
      },
    },
    {
      name: 'Jane',
      parent: {
        profile_img: {
          uid: 'u293k4'
        },
      }
    },
  ],
  occupation: {
    past: 'current',
    prior: {
      title: 'Accountant',
      company: {
        logo: {
          img: {
            uid: 'u29374'
          }
        }
      }
    }
  }
}

let imgs = [{
    uid: 'u2a3j4',
    format: 'jpg',
    alt_txt: 'Lorem...',
    size: 583729,
    dominant_color: '#d79273'
  },
  {
    uid: 'u5j3vg',
    format: 'png',
    alt_txt: 'Lorem...',
    size: 284849,
    dominant_color: '#f99383'
  },
  {
    uid: 'u2726b',
    format: 'gif',
    alt_txt: 'Lorem...',
    size: 293742,
    dominant_color: '#349a83'
  }
]

console.log(decorate(datapile, imgs))

CodePudding user response:

You need to recurse in the nested datapile to identify the object with uids and add the img properties to be added.

Few cases to consider:

  1. Objects. (If the Object has uid property, then stop recursion for its properties)
  2. Object values having objects.
  3. Array of Objects.

No need to return anywhere in your function actually as we can update objects inline.

Try like below.

let imgs = [ { uid: "u2a3j4", format: "jpg", alt_txt: "Lorem...", size: 583729, dominant_color: "#d79273", }, { uid: "u5j3vg", format: "png", alt_txt: "Lorem...", size: 284849, dominant_color: "#f99383", }, { uid: "u2726b", format: "gif", alt_txt: "Lorem...", size: 293742, dominant_color: "#349a83", }, { uid: "u293k4", format: "gif", alt_txt: "Lorem...", size: 193742, dominant_color: "#349a83", }, { uid: "u29374", format: "gif", alt_txt: "Lorem...", size: 793742, dominant_color: "#349a83", }, ]; let datapile = { cover_img: { uid: "u2a3j4" }, avatar_img: { uid: "u5j3vg" }, created: 8273736384, friends: [ { name: "John", img: { uid: "u2726b" } }, { name: "Jane", parent: { profile_img: { uid: "u293k4" } } }, ], occupation: { past: "current", prior: { title: "Accountant", company: { logo: { img: { uid: "u29374" } }, }, }, }, };

function isArray(x) {
  return x !== undefined && Array.isArray(x);
}
function isObject(x) {
  return typeof x === "object" && !Array.isArray(x);
}
function get_item(uid) {
  return imgs.find((img) => img.uid === uid);
}

function append_referenced_relations(data) {
  if (isObject(data)) {
    if (data["uid"] !== undefined) {
      const img = get_item(data.uid);
      // Add img properties to the same object as properties
      Object.entries(img).forEach(([key, value]) => {
        data[key] = value;
      });
    } else {
      // Recurse for the object values
      Object.values(data).forEach((item) => {
        append_referenced_relations(item);
      });
    }
  } else if (isArray(data)) {
    data.forEach((item) => {
      // Recurse for the array entries
      append_referenced_relations(item);
    });
  }
}

append_referenced_relations(datapile);

console.log(JSON.stringify(datapile, null, 2));

  • Related