Anyone Experimenting with Maps versus Objects in Meteor?

I recently found myself needing key-value pair lookup functionality while keeping entries sorted in order and got really excited about ES6 Maps.

After some research I made some benchmarks using my app’s data and code. I was getting much better performance with bulk insertion using Map. Around 100% faster than bulk inserting in a plain old javascript object (POJO) when inserting a few thousand entries.

However, when testing key-value lookup on real data in a 5000 iteration loop, the POJO was about about 68% faster actually. That took out some of the wind for me but…

The deal-breaker came when I realized that Map isn’t JSON stringify-able - which I need to send the data to various microservices that share data. ES6 Maps have to be converted to an Array or Object first. That blew out any performance test as this added a significant bit of time onto my use-cases.

Anyone found anything similar or different to the above? Curious if anyone is making use of them.

1 Like

Hey there,

sure Map is great, WeakMap too.
Map object are very performant when all the data is formated the same (same types for key / value).
Map and WeakMap have their usage :

  • WeakMap is great if you’re using referencing a lot, it make them unique, easily found, and easily removable.
  • Map is great to use on Objects where you need to iterate over the keys (Object.keys), also you can set all Symbols as key (Object, Array, Class, …). So if you have a large dataset that needs unique IDs based on multiple properties that are not stringifyable it’s great too.
1 Like

I seldom use maps, because they are mutable data structures. E.g. they are not suitable for state in react. Maps and weakmaps are good for stuff like caches.

Speaking about order: js object key order is preserved since es2015, but there is a catch that integer keys are sorted before any other key type. That can be nasty if you use a number as key that might be a integer or float. Because floats are converted to strings, so “1.1” comes after 2, because 1.1 is a string key.

so if you rely on keys on object, make sure to always use only string keys (or only integer keys, but i would prefer strings)

1 Like

Aren’t all Object keys converted to strings?

Off the top of my head here are some differences:

  • Key order: insertion order for Map, I don’t know about Object.
  • Key types: any type for Map, only String (1 gets converted to “1”) for Object.
  • Performance: Map implementation should be simple, execution should be predictable since implementation handles all uses the same way, Object implementation handles all kinds of cases differently because of the generic nature of Object.

I have use Map only for the first two points. Never had a case where performance was an issue.

actually no.

see https://codesandbox.io/s/nervous-river-d8vcx?file=/src/index.js

See how it changes the order and lists all pure integer keys first.

That is not a bug, that is spec’d like this due to backward compatibility probably

@macrozone Oh OK. Did not know about that! Keys that represent nonnegative integers are listed first in increasing order, while other keys are listed last in insertion order, but all keys are still converted to strings. Interesting… For instance

const obj = {};

obj[1] = 1;
obj[1.2] = 1.2;
obj[-2] = -2;
obj[1.3] = 1.3;
obj['string'] = 'string';
obj[NaN] = NaN;
obj[3] = 3;
obj[0] = 0;
obj["2"] = "2";
obj[2.2] = 2.2;
obj["-1"] = "-1";
obj[-0] = -0;
obj['NaN'] = 'NaN';

console.debug(obj);
{
  '0': -0,
  '1': 1,
  '2': '2',
  '3': 3,
  '1.2': 1.2,
  '-2': -2,
  '1.3': 1.3,
  string: 'string',
  NaN: 'NaN',
  '2.2': 2.2,
  '-1': '-1'
}
1 Like

thats even weirder :wink:

That’s exactly what I experienced. Our app uses a user-input string as the key in a cache that needs to stay in order (e.g think an Object of unique team names that are ranked but also need key lookup). So we hit some bugs when users input an integer as the input field. Things started sorting out of order.

I can confirm, it seems POJO key/value pairs do honor their initial insertion in a loop for example. I’m not sure about random insertions afterward. But as soon as a key is an Integer, the sorting breaks.

You can always add a second rankForSorting field but then you’re sorting again (on the client for example) when you don’t need to. Map had slower lookup for our tests and all keys are the same type of _id string in the benchmark. And lookup speed is important when looking up thousands of teams as quickly as possible.