对象或对象数组

我想在node.js中存储连接的socket'id(socket.io)和其他一些关于这些的信息。 原因是,我必须列出客户和他们的信息,否则我必须find一个由它的ID。 我能够只使用客户端连接时创build的socket对象。

我以为,如果一个客户端连接,我会'把'它的ID和附加信息的clientsvariables。

 var clients = /* this is the question */; io.on('connection', function(socket) { // I can't use `io` just the `socket` }) 

我对这个问题有两个想法,但是我不知道哪个是更好的结构来做这个,或者如果有很多客户端连接,哪个会更快,使用更less的内存?

目的:

唯一的ID是关键,数据存储在它的值。

 { '01234': { // ... }, '56789': { // ... } } 

对象数组:

对象存储在一个数组中,它们的唯一ID和数据也存储在它们中。

 [ { id: '01234' // ... }, { id: '56789' // ... } ] 

性能和内存哪个更快或更好? 或者有没有其他解决scheme呢?

在内存方面,两种方法几乎完全相同。 将数据存储在对象或对象数组中不会影响内存消耗。

但是,在性能方面,如果您经常倾向于通过其ID来访问对象,那么将其作为关键字存储是个不错的主意。 你将不必循环通过集合的每个元素来find它的ID。

正如@Josh所说,虽然你正在创build一个可能很难处理的非标准的收集结构。

如果这是你的一个问题,你可以创build一个外部索引。

 sockets : [ {socket1}, {socket2}, {socket3} ] indexes : { socket1 : 0, socket2 : 1, socket3 : 2 } 

这样,通过它的id访问一个套接字,你可以通过索引对象中存储的索引来获取它在数组中的位置。 但是,你必须保持套接字数组和索引数组同步。

添加套接字很简单。 您将套接字添加到数组,并将该ID添加到索引。

 socket.on('add', function(socket){ var len = sockets.push(socket); indexes[socket.id] = len-1; }) 

删除更棘手。 当您“删除”或拼接一个数组时,所拼接的项目之后的所有索引都将递减。 那么你也必须减less你的所有索引。 你失去了performance。

更好的方法是不拼接数组,而是在删除它们时将套接字设置为“未定义”。 这样,即使在删除套接字时,也不必更新索引。

 socket.on('delete' function(socket){ sockets[indexes[socket.id]] = undefined; delete indexes[socket.id]; }) 

如果你的应用程序长时间运行,你将不得不重build每个约3000个请求索引左右,因为“未定义”将开始膨胀你的套接字/索引数组。

 function rebuildIndex(){ indexes = []; _.forEachRight(sockets, function(socket, index){ if (_.isUndefined(socket)) sockets.splice(index, 1) else indexes[socket.id] = index; }) } 

此外,你可以使用我写的库( 亲和力 ),这是一个关系代数库。 这个库允许在对象集合上创build索引(就像在数据库中一样),所以你仍然可以拥有一个“普通”的集合,同时对它进行基于索引的访问。

在这里检查一个工作的例子

 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() 

这是在关系中定义套接字的简单方法。 但是,您正在为id字段使用两倍的内存(因为它在套接字和ID列中被复制)。 如果你愿意,你也可以为每个套接字的属性创build一个列,就像数据库表一样,以防止重复ID字段:

 var sockets = new affinity.Relation([ {id : { type : affinity.Integer}}, {userId : {type : affinity.Integer}}, {openedDate : {type : affinity.Date}}, {token : {type : affinity.String}} // ... ],[],{ pk : 'id' }); 

//每个套接字都是关系中的一行。 访问如下属性:

sockets.restrict(sockets.get( 'ID')。当量( '29823'))。第一()

// …

两者都有优点和缺点。

使用对象:

 { '01234': { // ... }, '56789': { // ... } } 

你可以通过调用sockets[socketId]或者其他方法来做简单的查询。

如果您有一个集合( [{},{},{}] ),则每次要查找对象时都必须遍历集合:

 var socketIWant = sockets.filter(socket => id === 0123)[0]; // or whatever 

然而,“收集”模式是相当常见的,可能值得将这些数据保留在这个结构中,以便于以后的开发。

另外,如果您想要使用数据库来存储套接字信息,则通常可以直接遍历集合serverside并将其一对一地存储到NoSQL数据库中。

如果您select“对象对象”方法,则在查询或保存对象到数据库时可能需要执行一些数据操作:

 var sockets = { '0123': {} }; Objects.keys(sockets).forEach(function(key) { MyDB.save(_.assign(sockets[key], { _id: key })); }); 

或者像上面这样的东西。 一些可能无关的“数据消除”。 从数据库中迭代并保存/查询(如果存在的话),收集方法会简单一些。