Node.js mongo的简短用户友好ID

Node.js mongo的简短用户友好ID,node.js,mongodb,Node.js,Mongodb,我正在创建一个实时股票交易系统,并希望提供一个可读的,用户友好的方式来参考他们的订单的用户。例如,ID的长度应该类似于8个字符,并且只包含大写字符,例如Z9CFL8BA。由于显而易见的原因,id在系统中必须是唯一的 我使用MongoDB作为后端数据库,并评估了以下不符合我要求的项目 hashids.org-这看起来不错,但生成的ID太长: var mongoId = '507f191e810c19729de860ea'; var id = hashids.encodeHex(mongoId);

我正在创建一个实时股票交易系统,并希望提供一个可读的,用户友好的方式来参考他们的订单的用户。例如,ID的长度应该类似于8个字符,并且只包含大写字符,例如Z9CFL8BA。由于显而易见的原因,id在系统中必须是唯一的

我使用MongoDB作为后端数据库,并评估了以下不符合我要求的项目

hashids.org-这看起来不错,但生成的ID太长:

var mongoId = '507f191e810c19729de860ea';
var id = hashids.encodeHex(mongoId);
console.log(id)
结果是:1E6Y3Y4D7RGYHQ7Z3XVM4NNM

github.com/dylang/shortid-这要求您指定一个64字符的字母表,如前所述,我只想使用大写字符

function toBase36(id) {
  var half = Math.floor(id.length / 2);
  var first = id.slice(0, half);
  var second = id.slice(half);
  return parseInt(first, 16).toString(36).toUpperCase()
       + parseInt(second, 16).toString(36).toUpperCase();
}

我知道实现我所寻找的唯一方法可能是生成符合我要求的随机代码,然后检查数据库中是否存在冲突。如果是这种情况,在nodejs/mongodb环境中最有效的方法是什么?

您正在尝试将base-16(十六进制)转换为base-36(字母表中的26个字符加上10个数字)。一种简单的方法可能是简单地使用
parseInt
的基数参数来解析十六进制id,然后调用
.toString(36)
将其转换为base-36。这会将“507f191e810c19729de860ea”转换为“VDFGUZEA49X1V50356”,将长度从24个字符减少到18个字符

function toBase36(id) {
  var half = Math.floor(id.length / 2);
  var first = id.slice(0, half);
  var second = id.slice(half);
  return parseInt(first, 16).toString(36).toUpperCase()
       + parseInt(second, 16).toString(36).toUpperCase();
}
功能表36(id){
var半=数学楼层(id长度/2);
var first=id.slice(0,一半);
var second=id.slice(一半);
返回parseInt(first,16).toString(36).toUpperCase()
+parseInt(second,16).toString(36.toUpperCase();
}
//忽略下面的所有内容(仅用于演示)
函数转换(e){if(e.target.value.length%2==0)base36.value=toBase36(e.target.value)}
var base36=document.getElementById('base36');
var hex=document.getElementById('hex');
document.getElementById('hex')。addEventListener('input',convert,false);
转换({target:{value:hex.value}})
input{font-family:monospace;width:15em;}

我知道实现我所寻找的唯一方法可能是生成符合我要求的随机代码,然后检查数据库中是否存在冲突。如果是这种情况,在nodejs/mongodb环境中最有效的方法是什么

根据您的描述,您使用[0-9A-Z]范围内的8个字符作为“id”。那是36⁸ 组合(≈ 2.8211099E12)。假设你的交易系统在短期到中期内没有获得疯狂的巨大人气,那么发生冲突的可能性就相当低了

因此,您可以采取乐观的方法,生成一个随机id,其中包含以下代码行(正如@idbehold在评论中注意到的,请注意
Math.random
可能不够随机,因此可能会增加冲突的机会——如果您这样做,可能应该调查[1])

然后,在该字段上使用适当的唯一索引,您只需循环,重新生成一个新的随机ID,直到在尝试插入新事务时没有冲突为止。由于碰撞的可能性相对较小,因此应终止碰撞。大多数情况下,这将在第一次迭代时插入新文档,因为没有冲突

如果我没有大错特错的话,假设有100亿笔交易,第一次转弯时碰撞的概率仍然只有0.3%,第二次转弯时碰撞的概率略高于0.001%


[1] 在节点上,您可能更喜欢使用生成随机id。您可能会围绕此创建一些内容,可能:

> b = crypto.pseudoRandomBytes(6)
<SlowBuffer d3 9a 19 fe 08 e2>
> rid = b.readUInt32BE(0)*65536 + b.readUInt16BE(4)
232658814503138
> rid.toString(36).substr(0,8).toUpperCase()
'2AGXZF2Z'
>b=加密伪随机字节(6)
>rid=b.readUInt32BE(0)*65536+b.readUInt16BE(4)
232658814503138
>rid.toString(36).substr(0,8).toUpperCase()
“2AGXZF2Z”

小心
Math.random()
,因为它不够随机,与更好的随机数生成器相比,肯定会增加碰撞的机会。@idbehold Yes这是正确的。也许你们知道JavaScript上有更好的随机生成器吗?在节点上你们可以使用。@idbehold谢谢你们的建议。在这种情况下,,可能是一个更好的选择,因为我们不需要加密强伪随机数据——如果熵池耗尽,OP可能不想阻止。感谢大家的回复——您对如何在多线程环境中处理冲突解决过程有什么建议吗?在多线程环境中,可能会有多个线程检查已用ID表?我知道,随着时间的推移,以及已经使用的ID表越来越大,这将变得越来越没有性能。在mongodb中实现这一点的最佳方式是什么?感谢您的回复和代码。然而,18个字符仍然有点太长。我需要一些大约8个字符长的东西。