Suppose the following:
const socketTracker = new Map();
const addToSocketTracker = ({ userId, socketId }) => {
socketTracker.set({
socketId,
userId
}, {
sendMessage: function() {
return [`Socket ID: ${this.socketId}`, `User ID: ${this.userId}`].join('n')
}
});
}
addToSocketTracker({ userId: 123, socketId: 456 })
const element = socketTracker.get(({ userId }) => userId === 123); // this returns undefined
element?.sendMessage();
console.log('element', element);
Is it possible to access a specific key and then call sendMessage
as in the snippet?
3
Answers
It is, but it’s not efficient. You have to loop through the map’s keys:¹
In the given example, though, I don’t see any reason for
socketId
to be part of the key of the map. Fundamentally, key a map by what you’re going to use to look up its entries: justuserId
, in this case. If you also need to look up entries bysocketId
, you can have a separate map for that. Or if you need a compound key, you can use a map of maps.In particular, it doesn’t make sense to key a map by an object unless you will later have a reference to that same object to use to look up the map entry, since
Object.is({}, {})
isfalse
— no object is equal to any other object.A couple of notes on that:
You can avoid the intermediate array by writing a simple utility function to do a
find
-like operation on an iterable. Iterables are gettingfind
, though: https://github.com/tc39/proposal-iterator-helpers.And I guess technically you don’t need that conditional operator if you never use
undefined
as a key, justconst element = socketTracker.get(key);
would also work, giving youundefined
forelement
whenkey
wasundefined
.socketTracker.get(({ userId }) => userId === 123)
– you are trying to get element like with anArray::filter()
.Map::get()
actually accepts a key, not a callback.Map()
isn’t good for this scenario, useArray()
:Basically you are trying to use denormalized data where you have users with sockets. So better restructure (normalize) your data and make sockets as a part of a user object: