随机生成一个不在mongodb中的值?

时间:2013-12-28 19:01:00

标签: node.js mongodb random

我正在尝试在Node中生成会话ID并将它们存储在MongoDB中。对于我的应用程序,我只想生成一个随机的6位数字(这个数字用于同步两个会话,因此用户可以轻松复制)。我想生成一个尚未在MongoDB中的sessions集合中的数字。我的第一个想法可能会在99%的时间内起作用:

function GetSessionKey(cb) {
    var key = parseInt(Math.random() * 1000000).toString();
    while (key.length < 6) key = '0' + key;
    db.sessions.find({ Key: key }, function (err, docs) {
        if (!err && docs.length == 0) {
            cb(key);
        } else {
            GetSessionKey(cb);
        }
    });
}

但是生成的密钥很有可能不断选择mongo中的现有密钥。或者所有密钥都已被使用的可能性(我不希望发生这种情况)。

我知道Node是异步的但这是否意味着像这样的递归异步调用会在它被调用时填满堆栈?或者异步调用不会被放入堆栈?有没有更好的方法来生成短的唯一键?旧密钥将被删除,可以重复使用,所以我不认为它是一个滴答作响的定时炸弹。我只是担心随机方面可能会造成麻烦。

2 个答案:

答案 0 :(得分:3)

另一种方法是使用MongoDB来强制唯一性。例如,在Mongo shell中的Key字段上创建唯一索引:

db.sessions.ensureIndex( { Key: 1 }, { unique: true } )

修改Node.js代码以插入生成的随机值并测试err变量是否存在重复键错误。如果没有错误,你很高兴。否则,重新生成该值并重试。您可以测试重复键错误,如下所示:

...
db.sessions.insert({ Key: key }, function (err, docs) {
  ...
  if (err) {
    if (err.code && err.code == 11000) {
      // Duplicate key error. Generate a new random value and insert again.
    } else {
      throw err;
    }
  }
  ...

如果您可以将生成的密钥存储在_id字段而不是Key中,那么您可以跳过ensureIndex(...),因为MongoDB会自动在_id上创建唯一索引。< / p>

答案 1 :(得分:0)

递归异步调用不会填满堆栈。他们只是一遍又一遍地旋转cpu,直到他们找到一个键或某种错误发生。

我建议尽量在猜测量上设定合理的最大值。是的,base64(如上所述)或base36(简称.toString(36))会增加可用的密钥数量,如果您担心这一点,可以减少碰撞机会。

编辑:确实有更好的方法 - 顺序键。