3
\$\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
\$\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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.