Search code examples
javascriptmongodbmeteor

Cannot use Map read from MongoDb


I wrote a function that stores a Map object in MongoDb. However, when I read the object back elsewhere, as in:

var map=this.projectData.storedMap;
map.forEach ...

It states that map.forEeach is not a function. I tried let x=new Map() and assign the object but the result is still the same.

I use map because I need to ensure a particular order of properties (sorted).


Solution

  • Meteor supports complex custom data types via EJSON: https://docs.meteor.com/api/ejson.html

    Every insert will try to resolve complex objects for registered EJSON extensions! One thing though, it requires monkey patching the Map class. The following code defines a custom EJSON type for Map:

    import { EJSON } from 'meteor/ejson'
    
    Map.prototype.toJSONValue = function () {
      const self = this
      return [...self.entries()]
    }
    
    Map.prototype.typeName = function () {
      return 'Map';
    }
    
    EJSON.addType('Map', function fromJSONValue(entries) {
      return new Map(entries)
    })
    

    This example shows, that the order of the the keys is preserved even after the value has been set again:

    const map = new Map()
    
    map.set('foo', 1)
    map.set('bar', 3)
    map.set('baz', 5)
    map.set('moo', 7)
    map.set('foo', 11) // set again
    
    const dataStr = EJSON.stringify({ data: map })
    
    // {"data":{"$type":"Map","$value":[["foo",11],["bar",3],["baz",5],["moo",7]]}}
    
    EJSON.parse(dataStr)
    // { data: Map(4) { 'foo' => 11, 'bar' => 3, 'baz' => 5, 'moo' => 7 } }
    

    Important here is to use map.entries() which returns an iterator that preservers insertion order, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries