1

I am trying to search for specific nodes within an object and display a new object with the required data. There could be single or multiple fields in each composite type like displayed below.

This is the original object:

{
  "section": "personal",
  "fields": [
    {
      "type": "composite",
      "name": "name",
      "label": "Name",
      "fields": [
        {
          "type": "text",
          "name": "given",
          "label": "First name",
          "value": "Joe"
        },
        {
          "type": "text",
          "name": "family",
          "label": "Last name",
          "value": "Smith"
        }
      ]
    },
    {
      "type": "composite",
      "name": "address",
      "label": "Address",
      "fields": [
        {
          "type": "text",
          "name": "streetName",
          "label": "Street Name",
          "value": "1 High St"
        },
        {
          "type": "text",
          "name": "city",
          "label": "City",
          "value": "New York"
        }
      ]
    }
  ]
}

The resulting object should look like this:

{
  name: {
    given: "Joe",
    family: "Smith",
  },
  address: {
    streetName: "1 Hight St",
    city: "New York"
  }
}

EDIT*** Ideally, I'd like to figure out a way to use javascript methods (map/reduce/filter) and/or lodash to come up with an answer.

This is more an outline of what i've been looking at so far with built in methods.

var convertVals = function() {

  var data = fields.fields;
  var filter = data.filter(function(form) {
    return form
  })
  .filter(function(form) {
    return form.name && form.fields;
  })
  .map(function(form) {
    return {form.name, [form.name.name]: form.name.value};
  })
};
convertVals();

Thanks,

2
  • 1
    Not certain what question is? Can you include javascript that you have tried to meet requirement? See stackoverflow.com/help/how-to-ask Commented Mar 18, 2017 at 3:15
  • Hi @guest271314, added some pseudocode into what I was thinking, but struggling to get it to filter down to the final level, thanks. Commented Mar 19, 2017 at 6:37

3 Answers 3

1

You can use Array.prototype.reduce() to iterate nested fields arrays. Set "name" property value of parent object as property name of object with value set to object set to "name" and "value" properties of objects within child "fields" array

var data = {
  "section": "personal",
  "fields": [
    {
      "type": "composite",
      "name": "name",
      "label": "Name",
      "fields": [
        {
          "type": "text",
          "name": "given",
          "label": "First name",
          "value": "Joe"
        },
        {
          "type": "text",
          "name": "family",
          "label": "Last name",
          "value": "Smith"
        }
      ]
    },
    {
      "type": "composite",
      "name": "address",
      "label": "Address",
      "fields": [
        {
          "type": "text",
          "name": "streetName",
          "label": "Street Name",
          "value": "1 High St"
        },
        {
          "type": "text",
          "name": "city",
          "label": "City",
          "value": "New York"
        }
      ]
    }
  ]
}

var res = data.fields.reduce((o, {name, fields}) => 
           (o[name] = fields.reduce((curr, {name:key, value}) =>
             (curr[key] = value, curr),{}), o), {});

console.log(res);

Sign up to request clarification or add additional context in comments.

Comments

1

Well, here you go! Figured I might as well take a crack at it as no more questions were coming in.

var originalObject = {
  "section": "personal",
  "fields": [
    {
      "type": "composite",
      "name": "name",
      "label": "Name",
      "fields": [
        {
          "type": "text",
          "name": "given",
          "label": "First name",
          "value": "Joe"
        },
        {
          "type": "text",
          "name": "family",
          "label": "Last name",
          "value": "Smith"
        }
      ]
    },
    {
      "type": "composite",
      "name": "address",
      "label": "Address",
      "fields": [
        {
          "type": "text",
          "name": "streetName",
          "label": "Street Name",
          "value": "1 High St"
        },
        {
          "type": "text",
          "name": "city",
          "label": "City",
          "value": "New York"
        }
      ]
    }
  ]
};

function convertVals(obj){
  var retObj = {};
  for(var i=0;i<obj.fields.length;i++){
    var tempObj={};
    for(var j=0;j<obj.fields[i].fields.length;j++){
      tempObj[obj.fields[i].fields[j].name] = obj.fields[i].fields[j].value;
    }
    retObj[obj.fields[i].name] = tempObj;
  }
  return retObj;
}

console.log(convertVals(originalObject));
/*
Should return:

{
  name: {
    given: "Joe",
    family: "Smith",
  },
  address: {
    streetName: "1 Hight St",
    city: "New York"
  }
}
*/

2 Comments

Thanks, I was looking to javascript methods for a solution, but could have tried the loop.
You're welcome. I usually end up doing loops, because I have greater control over them and I don't know all of the built-in methods.
1

Here's a lodash solution that uses keyBy to assign the keys for each fields and mapValues to get the value for each field.

function getFields(data) {
  return data.value || _(data.fields)
    .keyBy('name')
    .mapValues(getFields)
    .value();
}

var data = {
  "section": "personal",
  "fields": [{
      "type": "composite",
      "name": "name",
      "label": "Name",
      "fields": [{
          "type": "text",
          "name": "given",
          "label": "First name",
          "value": "Joe"
        },
        {
          "type": "text",
          "name": "family",
          "label": "Last name",
          "value": "Smith"
        }
      ]
    },
    {
      "type": "composite",
      "name": "address",
      "label": "Address",
      "fields": [{
          "type": "text",
          "name": "streetName",
          "label": "Street Name",
          "value": "1 High St"
        },
        {
          "type": "text",
          "name": "city",
          "label": "City",
          "value": "New York"
        }
      ]
    }
  ]
};

function getFields(data) {
  return data.value || _(data.fields)
    .keyBy('name')
    .mapValues(getFields)
    .value();
}

console.log(getFields(data));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

There is a hidden implication in the solution above, if the value contains falsey values then it would dismiss this value instead and assume that there's a fields value. To solve this, we can use has to check if a value key exists and then perform the same operations that we did above.

function getFields(data) {
  return _.has(data, 'value')? data.value: 
    _(data.fields)
    .keyBy('name')
    .mapValues(getFields)
    .value();
}

var data = {
  "section": "personal",
  "fields": [{
      "type": "composite",
      "name": "name",
      "label": "Name",
      "fields": [{
          "type": "text",
          "name": "given",
          "label": "First name",
          "value": "Joe"
        },
        {
          "type": "text",
          "name": "family",
          "label": "Last name",
          "value": "Smith"
        }
      ]
    },
    {
      "type": "composite",
      "name": "address",
      "label": "Address",
      "fields": [{
          "type": "text",
          "name": "streetName",
          "label": "Street Name",
          "value": "1 High St"
        },
        {
          "type": "text",
          "name": "city",
          "label": "City",
          "value": "New York"
        }
      ]
    }
  ]
};

function getFields(data) {
  return _.has(data, 'value')? data.value: 
    _(data.fields)
    .keyBy('name')
    .mapValues(getFields)
    .value();
}

console.log(getFields(data));
body > div { min-height: 100%; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>

2 Comments

Right on - thanks @ryeballar. I think the second one makes sense as it may as well!
@randomInput I edited my answer into a clean recursive approach. It's basically the same with the previous answer, I just moved the conditionals outside the mapValues callback.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.