Map and object: converting nested objects

When we want to save the contents of a JavaScript Map structure in a file, we must transform it into a string. This would be very simple with the JSON.stringify() method, but it does not work on new JavaScript structures like Map, Set, etc ... However, it works on a classic structure like Array or an object. So with an additional step, by turning the Map into an object, Map persistence becomes easy.

To retrieve the data from the file, we'll use JSON.parse() to convert the string to an object and then we convert that object to a Map.

The function entries() of Object, produces a Map from an object, so the conversion could be done with a single command:

var m = new Map(Object.entries(o))

But we will see later that it is a little more complicated than that.

Converting a Map to an object

Let's try first with this simple function:

var o = {}
var m = Map([ 
 [ "a", "one"], 
 [ "b": "two"], 
 [ "c": "three"],
 [ "d": new Map([ [ "e": "four"] ]) ]
]) 	
     
function mapToObject(o, m) {
    for(let[k,v] of m) { o[k] = v }
}
console.log(JSON.stringify(mapToObject(o, m), null, ' '))
Result

The Map has become an object, but we have a problem, the nested Map associated with the key "d" is not converted. To process nested Map, we have defined a recursive function ...

function mapToObjectRec(m) {
    let lo = {}
    for(let[k,v] of m) {
        if(v instanceof Map) {
            lo[k] = mapToObjectRec(v)
        }
        else {
            lo[k] = v
        }
    }
    return lo
}

var o2 = mapToObjectRec(m)
console.log(JSON.stringify(mapToObject(o2, m), null, ' '))
Result

The Map associated with the key "d" is well converted into an object and thus we can save all the contents, for example with this command of Node.js:

fs.writeFileSync(filename, JSON.stringify(o2, null, ' '));

Converting an object to a Map

To retrieve the data in the file, the reverse conversion must be done.

Although, as we have seen, it is possible to do this conversion with a single instruction when the object contains only primitive values, we encounter the same problem as before with nested objects: they are not converted into Map structures, they are directly associated with the keys. We would obtain after conversion the following result:

var m = new Map([ 
 [ "a", "one"], 
 [ "b", "two"], 
 [ "c", "three"],
 [ "d", [Object]]
]) 

Which is not usually what you want.

A recursive function is also necessary here to take into account nested objects which we have defined below.

var data = fs.readFileSync(fname,'UTF-8')
let o3 = JSON.parse(data)

// We will get the following object:

{
  "a": "one",
  "b": "two",
  "c": "three",
  "d": { "e": "four"}
}	

function objectToMap(o) {
    let m = new Map()
    for(let k of Object.keys(o)) {
        if(o[k] instanceof Object) {
            m.set(k, objectToMap(o[k]))   
        }
        else {
            m.set(k, o[k])
        }    
    }
    return m
}

var m2 = objectToMap(o3)
console.log(m2.get("d").get("e"))
Result

In this example, we read the value associated with the key "e" of the nested Map, which is associated with the key "d", and it displays "four" which proves to us that we have reconstituted the Map structure in whole.

© 4 avril 2018 Xul.fr