Both approaches will be almost exactly the same in terms of memory. Storing data in objects or array of objects will not affect the memory consumption.
Performance-wise, though, if you often tend to access objects by their id, it's a good idea to store it as a key. You won't have to loop through each element of the collection to find it by it's id.
As @Josh said, though, you are creating a non-standard collection structure which might be difficult to work with.
If this is a concern to you, you could create an external index.
sockets : [ {socket1}, {socket2}, {socket3} ]
indexes : { socket1 : 0, socket2 : 1, socket3 : 2 }
This way, to access a socket by it's id, you can get it's position in the array by it's index stored in the indexes object. Though, you'll have to keep the sockets array and the indexes array in sync.
When adding sockets is easy. You add the socket to the array and the id to the index.
socket.on('add', function(socket){
var len = sockets.push(socket);
indexes[socket.id] = len-1;
})
Deleting is trickier. When you "delete" or splice an array, all indexes after the spliced item will be decremented. You'd then have to also decrement all your indexes. You lose in performance.
A better approach would be to not splice the array, but to set the sockets to "undefined" when deleting them. This way, even when deleting a socket, you don't have to update your index.
socket.on('delete' function(socket){
sockets[indexes[socket.id]] = undefined;
delete indexes[socket.id];
})
If your application is long running, you'd have to rebuild your indexes every maybe 3000 requests or so, as the "undefined" will start to bloat up your sockets/index array.
function rebuildIndex(){
indexes = [];
_.forEachRight(sockets, function(socket, index){
if (_.isUndefined(socket)) sockets.splice(index, 1)
else indexes[socket.id] = index;
})
}
Also, you could use a library I wrote (affinity) which is a relational algebra library. This library allow the creation of indexes on collection of objects (much like in a database), so you can still have a "normal" collection while having an index-based access on it.
Check here for a working example
var sockets = new affinity.Relation([
{id : { type : affinity.Integer}},
{socket : {type : affinity.Object}}
],[],{
pk : 'id'
});
sockets.add(socket1);
sockets.add(socket2);
// then to have only the sockets array (to interact with db maybe)
var socketObjs = sockets.project(['socket']).elements()
this is the simple way of defining your sockets in a relation. Though, you are using twice the memory for the id field (as it is duplicated in the socket and in the ID column). If you wanted, you could also create a column for each of the socket's properties, much like a database table to prevent the duplication of the ID field :
var sockets = new affinity.Relation([
{id : { type : affinity.Integer}},
{userId : {type : affinity.Integer}},
{openedDate : {type : affinity.Date}},
{token : {type : affinity.String}}
// ...
],[],{
pk : 'id'
});
// Each socket is a row in the relation. Access the properties like :
sockets.restrict(sockets.get('id').eq('29823')).first()
// ...