2

I have 2 sources of data. One of the sources is the "template" to what is acceptable for the data. However, the second source may have a large amount of data that I don't care about (100+ properties in the JSON). Here are the schemas:

// Only store the data we care about.  Only a small subset of
// data that I need for this particular dataset.
state = {
    isDirty: false,
    data: {
        name: '',
        address: '',
        city: '',
        state: ''
    }
 }

The second source will have the 4 attributes in the data schema above (plus many many more I don't care about). Currently, I am assigning them like this:

let updatedData = {};

for(const key in this.state.data) {
  updatedData[key] = someDataSource[key];
}

this.state.data = updatedData;

Using ES6, and perhaps destructing, is there a better way to mass assign variables like this?

Thanks again!

EDIT

Added for clarification the assignment after the loop.

Sean
  • 2,496
  • 7
  • 32
  • 60
  • Why not just use [`Object.assign()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)? But, if there are lots of properties you don't care about, I'm not sure why you're trying to copy all the properties. Might be better to make an array of the properties you do care about and just copy those or just specify those using destructuring. – jfriend00 May 31 '18 at 00:39
  • 2
    I think the `for` loop is perfectly fine, there's no great way to destructure only some properties of an object into another without writing your own function - an oft-reoccurring question here – CertainPerformance May 31 '18 at 00:41
  • but, @CertainPerformance - OP wants all of state.data ... not some of state.data – Jaromanda X May 31 '18 at 00:41
  • 1
    `let updatedData = Object.keys(this.state.data).reduce((o, k) => (o[k] = someDataSource[k], o), {});`. I bet the `for` loop doesn't look so bad now. – ibrahim mahrir May 31 '18 at 00:43
  • as `{...state.data};` is "stage 3" - perhaps `let updatedData = Object.assign({},state.data);` – Jaromanda X May 31 '18 at 00:44
  • @JaromandaX He is not copying from `this.state.data`, see. He is copying from `someDataSource` using the keys from `this.state.data` – ibrahim mahrir May 31 '18 at 00:46
  • @JaromandaX Ooops! Haven't used `Array#reduce` in two days and I'm begining to forget about it. Thanks! – ibrahim mahrir May 31 '18 at 00:48
  • yeah, just realised what the code is doing ... – Jaromanda X May 31 '18 at 00:50
  • Possible duplicate of [ES6 - Destructuring assignment - Unpack some properties from existing object to a new object?](https://stackoverflow.com/questions/50488096/es6-destructuring-assignment-unpack-some-properties-from-existing-object-to) – Jared Smith May 31 '18 at 00:54
  • Not really a duplicate because properties aren't listed explicitly. – Estus Flask May 31 '18 at 06:56

3 Answers3

1

Lodash pick can be used to pick specific keys, or helper function can be used for same purpose:

const pick = (obj, keys) => Object.keys(obj)
    .filter((key) => keys.indexOf(key) >= 0)
    .reduce(
        (newObj, key) => Object.assign(newObj, { [key]: obj[key] }),
        {}
    );

This is already suggested in many related questions. The thing that is specific to this question is:

this.state.data = pick(someDataSource, Object.keys(this.state.data));
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

A trick you can do (trick because it requires to swallow an error) is to use an non extensible object, using the Object.preventExtensions and then use Object.assign to fill it with data (in a try/catch block).

// Only store the data we care about.  Only a small subset of
// data that I need for this particular dataset.
state = {
    isDirty: false,
    data: {
        name: '',
        address: '',
        city: '',
        state: ''
    }
 }

const newData = {
    name:'name',
    address:'address',
    city:'city',
    state:'state',
    phone:'phone',
    zip:'zip'
}

const updatedData = Object.preventExtensions({...state.data});

try{
   Object.assign(updatedData, newData);
} catch(throwaway){};

console.log(updatedData);

And as a function for reuse

function schemaMerge(schema, data) {
  const mergedData = Object.preventExtensions({...schema});

  try {
    Object.assign(mergedData, data);
  } catch (throwaway) {};
  
  return ({...mergedData}); // create a new object from the merged one so that it no longer is extensionless
}

// Only store the data we care about.  Only a small subset of
// data that I need for this particular dataset.
state = {
  isDirty: false,
  data: {
    name: '',
    address: '',
    city: '',
    state: ''
  }
}

const newData = {
  name: 'name',
  address: 'address',
  city: 'city',
  state: 'state',
  phone: 'phone',
  zip: 'zip'
}


const updatedData = schemaMerge(state.data, newData);

state.data = updatedData;

console.log(state.data);
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
0

Properties can be excluded and modified in the JSON.parse reviver :

var o = JSON.parse('{"a":1, "b":2}', (k, v) => k === 'a' ? void 0 : k === 'b' ? 3 : v)

console.log( o )
Slai
  • 22,144
  • 5
  • 45
  • 53