5
\$\begingroup\$

I have an app with a bunch of questions defined in a yaml file. For various reasons I would like the data to be divided into sections (section_0, section_1, section_2 etc.). When I load this file into my js app I get an object that looks like this:

const questionData = {
  "section_0": {
    "items": [
      {
        "key": "0.0",
        "title": "Question one",
        "type": "integer"
      },
      {
        "key": "0.1",
        "title": "Question 0.1",
        "type": "integer"
      }
    ]
  },
  "section_1": {
    "items": [
      {
        "key": "1.0",
        "title": "Some title",
        "type": "integer",
        "options": {
          "1": "one",
          "2": "two",
          "3": "other option"
        }
      },
      {
        "key": "1.1",
        "title": "Question 1.1",
        "description": "Longer description text",
        "type": "string"
      },
      {
        "key": "1.2",
        "title": "Question 1.2",
        "type": "integer",
        "options": {
          "0": "option zero",
          "1": "option one",
          "2": "option two"
        }
      },
      {
        "key": "1.3",
        "title": "Q 1.2",
        "type": "boolean",
        "options": {
          "true": "Yes",
          "false": "No"
        }
      },
      {
        "key": "1.4",
        "title": "Question 1.4",
        "type": "string"
      },
      {
        "key": "1.5",
        "title": "Question 1.5",
        "type": "integer"
      },
      {
        "key": "1.6",
        "title": "Question 1.6",
        "type": "integer"
      },
      {
        "key": "1.7",
        "title": "Q1.7",
        "type": "integer"
      }
    ]
  }
}

(a lot more questions and sections in the actual app)

Now I would like to be able to query for a question by the key. I found/figured out two ways to do this. One is sort of home made and the other flattens the array using lodash.

Traversing the object:

function findByKey(data, key){
    if (data.hasOwnProperty('key') && data['key'] === key) {
      return data;
    }

    for (let i = 0; i < Object.keys(data).length; i++) {
      if (typeof data[Object.keys(data)[i]] === 'object') {
        let obj = findByKey(data[Object.keys(data)[i]], key);
        if (obj != null) {
          return obj;
        }
      }
    }

    return null;
}

findByKey(questionData, "0.1")
// => returns the object with the key "0.1"

Using lodash to create a flat array of objects:

const questionsArray = _.flatten(_.map(_.keys(questionData), function(val) {
  return questionData[val].items;
}));

_.find(questionsArray, function(obj) { return obj.key === "0.1" })
// => returns the object with the key "0.1"

Do I need to transform the questionData object like this just to be able to query for an object somewhere in the tree or am I missing some simpler solution (other than not creating the nested structure in the first place)?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

I usually have methods to normalize data in the format I want it so you don't have to iterate again. If you want you can have Schema that provides you methods or access to the data using custom methods.

var questions = new QuestionsSchema(data); // Normalizes to preferred format    questions.getOriginal(); // => Access to the original object 
questions.getQuestion('0.1');    // =>      {"key": "0.0","title": "Question one","type": "integer"}
questions.getSection('section_1'); // => whole section

I like more the composed functions you build, is a more like functional way.

\$\endgroup\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.