1

I have the following query string:

student.name.firstname=Foo&student.name.lastname=Bar&student.address=My%20Street

How to convert to nested object like this:

{
  student:{
    name:{
      firstname: "Foo",
      lastname: "Bar"
    },
    address: "My Street"
  }
}

I have tried the following code but something is wrong:

function convertQueryToMap(query) {
    var params = {};
    var vars = query.split('&');
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split('=');
        var subpairs;
        if (pair[0].includes('.')) {
            subpairs = pair[0].split('.');
            var object = {};
            subpairs.reduce(function(o, s, i) {
                if (i === subpairs.length-1) {
                    return o[s] = decodeURIComponent(pair[1]);
                } else {
                    return o[s] = {};
                }
            }, object);
        }
    }
    return params;
}

Do you know a solution?

smartmouse
  • 13,912
  • 34
  • 100
  • 166
  • I presume the `address` should not be part of the `name` object? – Bergi Oct 12 '19 at 15:51
  • You'll want to `reduce` onto the `params`, not onto that `object` which you create again for each key-value pair. And then only create a new sub-object `o[s] = {}` when it does not already exist. – Bergi Oct 12 '19 at 15:53
  • Also drop the `if (pair[0].includes('.'))`. You'll want to create values for non-nested keys as well? – Bergi Oct 12 '19 at 15:55
  • @Bergi: it was a typo, I edited my question. Thank you. – smartmouse Oct 12 '19 at 16:06

2 Answers2

4

You can use reduce method to create nested structure and split method to split the query first on parts based on & and also to get key and value from each part.

const query = 'student.name.firstname=Foo&student.name.lastname=Bar&student.address=My%20Street'

const toObject = string => {
  return string.split('&').reduce((r, s) => {
    const [key, val] = s.split('=');

    key.split('.').reduce((a, e, i, ar) => {
      return a[e] || (a[e] = (ar[i + 1] ? {} : val.replace(/%20/g, ' ')))
    }, r);

    return r;
  }, {})
}

const result = toObject(query);
console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
1

You could decode the string, split for parts, then for keys and value and assign the value to the nested object.

function setValue(object, keys, value) {
    var last = keys.pop();
        
    keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}

var string = 'student.name.firstname=Foo&student.name.lastname=Bar&user.address=My%20Street',
    result = {};
    
decodeURI(string).split('&').forEach(s => {
    var [key, value] = s.split('=');
    setValue(result, key.split('.'), value);
});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392