对象或对象数组
Object or array of objects
我想在 node.js 中存储连接的套接字的 ID (socket.io) 和一些关于这些的其他信息。
原因是,我必须列出客户及其信息,或者我必须通过它的 ID 找到一个。
我只能使用客户端连接时创建的 socket
对象。
我认为如果有客户端连接,我会 'put' 它的 id 和 clients
变量的附加信息。
var clients = /* this is the question */;
io.on('connection', function(socket) {
// I can't use `io` just the `socket`
})
对于这个问题我有两个想法,但我不知道哪个结构更好,或者如果有很多客户端连接,哪个结构会更快并且使用更少的内存?
对象:
唯一的id是键,数据存储在它的值中。
{
'01234': {
// ...
},
'56789': {
// ...
}
}
对象数组:
对象存储在数组中,它们的唯一 ID 和数据也存储在其中。
[
{
id: '01234'
// ...
},
{
id: '56789'
// ...
}
]
性能和内存哪个更快或更好?
或者还有其他解决方案吗?
两者各有优缺点
使用对象:
{
'01234': {
// ...
},
'56789': {
// ...
}
}
您可以通过调用 sockets[socketId]
或其他任何方式进行非常简单的查找。
如果你有一个集合([{},{},{}]
),你每次要查找对象时都必须遍历集合:
var socketIWant = sockets.filter(socket => id === 0123)[0];
// or whatever
但是,"collection" 模式很常见,将数据保留在该结构中可能是值得的,以便在以后的开发中更直观。
此外,如果您想使用数据库来存储套接字信息,通常可以直接遍历收集服务器端并将其一对一存储到 NoSQL 数据库中。
如果您采用 "object of objects" 方法,则在查询或将对象保存到数据库时可能需要进行一些数据操作:
var sockets = { '0123': {} };
Objects.keys(sockets).forEach(function(key) {
MyDB.save(_.assign(sockets[key], { _id: key }));
});
或者类似上面的内容。一些可能无关的 "data munging"。收集方法会更简单一些,可以从数据库中迭代和save/query(如果存在的话)。
两种方法在内存方面几乎完全相同。将数据存储在对象或对象数组中不会影响内存消耗。
不过,在性能方面,如果您经常倾向于通过对象的 ID 访问对象,那么将其存储为键是个好主意。您无需遍历集合中的每个元素即可通过其 ID 找到它。
不过正如@Josh 所说,您正在创建一个可能难以使用的非标准集合结构。
如果您担心这一点,您可以创建一个外部索引。
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;
})
删除比较棘手。当你 "delete" 或拼接数组时,拼接项之后的所有索引都会递减。然后,您还必须递减所有索引。你失去了性能。
更好的做法是不拼接数组,而是在删除时将套接字设置为"undefined"。这样,即使删除套接字,也不必更新索引。
socket.on('delete' function(socket){
sockets[indexes[socket.id]] = undefined;
delete indexes[socket.id];
})
如果您的应用程序很长 运行,您必须每大约 3000 个请求重建一次索引,因为 "undefined" 会开始膨胀您的 sockets/index 数组.
function rebuildIndex(){
indexes = [];
_.forEachRight(sockets, function(socket, index){
if (_.isUndefined(socket)) sockets.splice(index, 1)
else indexes[socket.id] = index;
})
}
此外,您可以使用我编写的库 (affinity),它是一个关系代数库。该库允许在对象集合上创建索引(很像在数据库中),因此您仍然可以拥有一个 "normal" 集合,同时对其进行基于索引的访问。
检查 here 以获取工作示例
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 列中重复)。如果你愿意,你也可以为每个套接字的属性创建一个列,就像数据库一样 table 以防止 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').eq('29823')).first()
// ...
我想在 node.js 中存储连接的套接字的 ID (socket.io) 和一些关于这些的其他信息。
原因是,我必须列出客户及其信息,或者我必须通过它的 ID 找到一个。
我只能使用客户端连接时创建的 socket
对象。
我认为如果有客户端连接,我会 'put' 它的 id 和 clients
变量的附加信息。
var clients = /* this is the question */;
io.on('connection', function(socket) {
// I can't use `io` just the `socket`
})
对于这个问题我有两个想法,但我不知道哪个结构更好,或者如果有很多客户端连接,哪个结构会更快并且使用更少的内存?
对象:
唯一的id是键,数据存储在它的值中。
{
'01234': {
// ...
},
'56789': {
// ...
}
}
对象数组:
对象存储在数组中,它们的唯一 ID 和数据也存储在其中。
[
{
id: '01234'
// ...
},
{
id: '56789'
// ...
}
]
性能和内存哪个更快或更好? 或者还有其他解决方案吗?
两者各有优缺点
使用对象:
{
'01234': {
// ...
},
'56789': {
// ...
}
}
您可以通过调用 sockets[socketId]
或其他任何方式进行非常简单的查找。
如果你有一个集合([{},{},{}]
),你每次要查找对象时都必须遍历集合:
var socketIWant = sockets.filter(socket => id === 0123)[0];
// or whatever
但是,"collection" 模式很常见,将数据保留在该结构中可能是值得的,以便在以后的开发中更直观。
此外,如果您想使用数据库来存储套接字信息,通常可以直接遍历收集服务器端并将其一对一存储到 NoSQL 数据库中。
如果您采用 "object of objects" 方法,则在查询或将对象保存到数据库时可能需要进行一些数据操作:
var sockets = { '0123': {} };
Objects.keys(sockets).forEach(function(key) {
MyDB.save(_.assign(sockets[key], { _id: key }));
});
或者类似上面的内容。一些可能无关的 "data munging"。收集方法会更简单一些,可以从数据库中迭代和save/query(如果存在的话)。
两种方法在内存方面几乎完全相同。将数据存储在对象或对象数组中不会影响内存消耗。
不过,在性能方面,如果您经常倾向于通过对象的 ID 访问对象,那么将其存储为键是个好主意。您无需遍历集合中的每个元素即可通过其 ID 找到它。
不过正如@Josh 所说,您正在创建一个可能难以使用的非标准集合结构。
如果您担心这一点,您可以创建一个外部索引。
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;
})
删除比较棘手。当你 "delete" 或拼接数组时,拼接项之后的所有索引都会递减。然后,您还必须递减所有索引。你失去了性能。
更好的做法是不拼接数组,而是在删除时将套接字设置为"undefined"。这样,即使删除套接字,也不必更新索引。
socket.on('delete' function(socket){
sockets[indexes[socket.id]] = undefined;
delete indexes[socket.id];
})
如果您的应用程序很长 运行,您必须每大约 3000 个请求重建一次索引,因为 "undefined" 会开始膨胀您的 sockets/index 数组.
function rebuildIndex(){
indexes = [];
_.forEachRight(sockets, function(socket, index){
if (_.isUndefined(socket)) sockets.splice(index, 1)
else indexes[socket.id] = index;
})
}
此外,您可以使用我编写的库 (affinity),它是一个关系代数库。该库允许在对象集合上创建索引(很像在数据库中),因此您仍然可以拥有一个 "normal" 集合,同时对其进行基于索引的访问。
检查 here 以获取工作示例
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 列中重复)。如果你愿意,你也可以为每个套接字的属性创建一个列,就像数据库一样 table 以防止 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').eq('29823')).first()
// ...