Home > OS >  Nested json payload and nested array javascript interview
Nested json payload and nested array javascript interview

Time:10-26

Got this as a assesment test for frontend position on coderbyte.com

We have many different APIs and services it integrates with. Frequently, on the front end, we integrate with many different product recommendation providers. This typically looks like a carousel of recommended products from a retailer that customers would consider purchasing if interested. API providers of product recommendations have all different types of API responses, but there is a common pattern which we will try to take advantage of in code below.

Write a function which receives a JSON payload and a configuration object as arguments and returns an array of arrays of mapped properties from the JSON payload to enumerable values for rendering a carousel. The JSON payload will always contain a nested array which will contain nested data about each product to be displayed in the carousel. It is up to you to define the configuration object used to read the nested array and map the nested product properties.

Try to write the most efficient and concise code you can. Using modern functional methods is highly recommended, but not required.

Example 1

JSON Payload Input

  "payload": [
    {
      "data": [
        [
          {
            "name": "Handbag",
            "url": "https://example.com/products/handbag",
            "images": {
              "small": "https://example.com/products/handbag/images/small.png",
              "medium": "https://example.com/products/handbag/images/medium.png",
              "large": "https://example.com/products/handbag/images/large.png"
            },
            "color": "black",
            "price": "$50.00"
          }
        ],
        [
          {
            "name": "Shoes",
            "url": "https://example.com/products/shoes",
            "images": {
              "small": "https://example.com/products/shoes/images/small.png",
              "medium": "https://example.com/products/shoes/images/medium.png",
              "large": "https://example.com/products/shoes/images/large.png"
            },
            "color": "red",
            "price": "$35.00"
          }
        ]
      ]
    }
  ]
}

Expected output

  [
    { type: 'TEXT', value: 'Handbag' },
    { type: 'URL', value: 'https://example.com/products/handbag' },
    { type: 'IMAGE', value: 'https://example.com/products/handbag/images/medium.png' },
    { type: 'TEXT', value: '$50.00' }
  ],
  [
    { type: 'TEXT', value: 'Shoes' },
    { type: 'URL', value: 'https://example.com/products/shoes' },
    { type: 'IMAGE', value: 'https://example.com/products/shoes/images/medium.png' },
    { type: 'TEXT', value: '$35.00' }
  ]
]

Example 2

JSON Payload Input

[
  [
    {
      "product_id": "000001",
      "meta": {
        "en_US": {
          "product_name": "Handbag",
          "product_urls": ["https://example.com/products/handbag"],
          "product_image_small": "https://example.com/products/handbag/images/small.png",
          "product_image_medium": "https://example.com/products/handbag/images/medium.png",
          "product_image_large": "https://example.com/products/handbag/images/large.png",
          "product_price_cents": 5000,
          "product_custom_attributes": {
            "product_price_string": "$50.00",
            "product_color": "black"
          }
        }
      }
    },
    {
      "product_id": "000002",
      "meta": {
        "en_US": {
          "product_name": "Shoes",
          "product_urls": ["https://example.com/products/shoes"],
          "product_image_small": "https://example.com/products/shoes/images/small.png",
          "product_image_medium": "https://example.com/products/shoes/images/medium.png",
          "product_image_large": "https://example.com/products/shoes/images/large.png",
          "product_price_cents": 3500,
          "product_custom_attributes": {
            "product_price_string": "$35.00",
            "product_color": "red"
          }
        }
      }
    }
  ]
]

Expected Output

[
  [
    { type: 'TEXT', value: 'Handbag' },
    { type: 'URL', value: 'https://example.com/products/handbag' },
    { type: 'IMAGE', value: 'https://example.com/products/handbag/images/medium.png' },
    { type: 'TEXT', value: '$50.00' }
  ],
  [
    { type: 'TEXT', value: 'Shoes' },
    { type: 'URL', value: 'https://example.com/products/shoes' },
    { type: 'IMAGE', value: 'https://example.com/products/shoes/images/medium.png' },
    { type: 'TEXT', value: '$35.00' }
  ]
]

My solution was not dynamic enough to parse both the input payloads. It works with Example 1

My Solution

var config = {
    name: {type :"TEXT", label: "name",  key: "name"},
    url: {type :"URL", label: "url", key: "url"},
    images: {type :"IMAGE", label: "image", key: "image", value: "medium"},
    price: {type :"TEXT", label: "price",  key: "price"},
}

function processData(payload, config) {
    function getImage(obj, key) {
      return  Object.keys(obj).reduce((acc, cur) => {
            
            if (cur.includes(key)) {
                acc = acc   obj[cur];
            }
            return acc;
        }, "")
    }
    return payload.payload[0].data.reduce(function(acc, cur) {
            var temp = [];
            Object.keys(config).forEach(function(c) {
                    console.log(c)
                    if (c == "images") {
                        var res = getImage(cur[0][c], config[c]["value"]);
                        var ob = {
                            type: config[c]["type"],
                            value: res
                            }
                            temp.push(ob);
                        }
                        else {
                            
                            temp.push({
                               type: config[c]["type"],
                                value: cur[0][c]
                            })
                        }
                        
                    });
                acc.push(temp);
                return acc
            }, [])
    }

CodePudding user response:

EDIT: Whoops, forgot the config

Try to write the most efficient and concise code

Sure... for me "efficient" means "understandable" - if they wanted performance they should have said "performant" isntead :). And concise code... well, that doesn't always mean quality code, so I'll try to balance.

My approach would be to at least somewhat unify the data, then use smaller functions and deal with the super confusing data structure there.

If this was a very big project and a more generic project would actually be needed, only then would I consider making anything generic with such data. Often it's not actually necessary and just introduces a whole lot of complexity.

const payload1 = [
  {
    data: [
      [
        {
          name: "Handbag",
          url: "https://example.com/products/handbag",
          images: {
            small: "https://example.com/products/handbag/images/small.png",
            medium: "https://example.com/products/handbag/images/medium.png",
            large: "https://example.com/products/handbag/images/large.png",
          },
          color: "black",
          price: "$50.00",
        },
      ],
      [
        {
          name: "Shoes",
          url: "https://example.com/products/shoes",
          images: {
            small: "https://example.com/products/shoes/images/small.png",
            medium: "https://example.com/products/shoes/images/medium.png",
            large: "https://example.com/products/shoes/images/large.png",
          },
          color: "red",
          price: "$35.00",
        },
      ],
    ],
  },
];

const payload2 = [
  [
    {
      product_id: "000001",
      meta: {
        en_US: {
          product_name: "Handbag",
          product_urls: ["https://example.com/products/handbag"],
          product_image_small: "https://example.com/products/handbag/images/small.png",
          product_image_medium: "https://example.com/products/handbag/images/medium.png",
          product_image_large: "https://example.com/products/handbag/images/large.png",
          product_price_cents: 5000,
          product_custom_attributes: {
            product_price_string: "$50.00",
            product_color: "black",
          },
        },
      },
    },
    {
      product_id: "000002",
      meta: {
        en_US: {
          product_name: "Shoes",
          product_urls: ["https://example.com/products/shoes"],
          product_image_small: "https://example.com/products/shoes/images/small.png",
          product_image_medium: "https://example.com/products/shoes/images/medium.png",
          product_image_large: "https://example.com/products/shoes/images/large.png",
          product_price_cents: 3500,
          product_custom_attributes: {
            product_price_string: "$35.00",
            product_color: "red",
          },
        },
      },
    },
  ],
];

// main function
const parseProducts = (data, config) => {
    const saneData = config.array ? data[0] : data[0].data;
    return saneData.map(product => {
        return [
            { type: 'TEXT',  value: getText(product, config) },   // 'Handbag'
            { type: 'URL',   value: getUrl(product, config) },    // 'https://example.com/products/handbag'
            { type: 'IMAGE', value: getImage(product, config) },  // 'https://example.com/products/handbag/images/medium.png'
            { type: 'TEXT',  value: getPrice(product, config) }   // '$50.00'
        ]
    });
};

const getText = (product, config) => {
    if (Array.isArray(product)) {
        return product[0].name;
    }
    const meta = product?.meta[config.lang];
    return meta?.product_name;
}

const getUrl = (product, config) => {
    if (Array.isArray(product)) {
        return product[0].url;
    }
    const meta = product?.meta[config.lang];
    return meta?.product_urls[0];
}

const getImage = (product, config) => {
    if (Array.isArray(product)) {
        return product[0].images.medium;
    }
    const meta = product?.meta[config.lang];
    return meta?.product_image_medium;
}

const getPrice = (product, config) => {
    if (Array.isArray(product)) {
        return product[0].price;
    }
    const meta = product?.meta[config.lang];
    return meta?.product_custom_attributes.product_price_string;
}

// Test
console.log(parseProducts(payload1, { array: 0 }));
console.log(parseProducts(payload2, { array: 1, lang: "en_US" }));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related