为Couchbase生成唯一的UInt32 ID

6
我正在寻找一种在nosql数据库中生成唯一ID的方法。与关系型数据库不同,没有行的概念,这意味着没有最后一行可以递增。
处理此问题的最常见方法是使用UUID。但我的问题是我需要添加另一个ID(而不是UUID),它需要满足以下要求:
- 唯一 - Unsigned Int32
总数据量可能达到大约50,000,000。因此,您如何生成相对唯一的uint32 ID?
UInt32值类型表示从0到4,294,967,295的带符号整数。
仅在新用户注册时生成ID。
每个新用户分配3个ID。
目前正在使用Couchbase Server。

它们会被生成多频繁?你可以使用自 Unix 纪元以来的毫秒。此外,CRC32? - Paul S.
可能每隔几分钟会发生一次。有时候它们可能同时发生,但这种情况不太可能。 - majidarif
@PaulS.:秒,对吧? - Ry-
@PaulS。我可以对用户名进行CRC32校验吗?因为用户名是唯一的,这些ID在注册时分配给每个用户,问题是,每个新注册用户应该分配3个数字。刚刚意识到CRC可能包含字母,所以行不通? - majidarif
1
@minitech 这看起来很有前途。你觉得它是否适合我的用例?你可以将其添加为答案。我会接受的。谢谢。 - majidarif
显示剩余5条评论
3个回答

4
这个问题已经解决了 - 我建议在Couchbase中使用原子增量(或减量)函数 - 这些是生成唯一ID的常见模式。
每当调用incr()方法时,它会原子地将计数器按指定值递增,并返回旧值,因此如果两个客户端同时尝试递增,它是安全的。
伪代码示例(我不是Node.JS专家!):
// Once, at the beginning of time we init the counter:
client.set("user::count", 0);
...
// Then, whenever a new user is needed: 
nextID = client.incr("user::count", 1); // increments counter and returns 'old' value.
newKey = "user_" + nextID;
client.add(newKey, value);

请参考Node.JS SDK,并查看Couchbase开发者指南中的使用参考文档进行查找部分,以获取完整的用法示例。

Inc和Dec似乎可以在文档内增加计数器时工作。那么在文档之间呢?我需要检查一下。我还在工作,等我有结果了会回来更新这里的。 - majidarif
@majidarif 如果你有一个文档,它一个计数器 - 例如对于用户ID,你可以有一个名为userid::count的文档,你可以使用incr()来生成下一个userID。 - DaveR
嗯,我不太明白。你能再解释一下吗?我应该获取最后一个计数并在插入新文档时将其增加吗?如果同时插入两个文档,这不会成为问题吗?如果它们得到相同的最后计数,怎么办? - majidarif
从您更新的答案中,我看到它确实增加了计数文档。但是下一个文档如何插入下一个数字呢?我应该先递增计数器,然后获取数字,然后插入新文档吗? - majidarif
如果您查看我提供的完整示例,您会发现调用incr()原子性的,它会增加计数器并返回先前的值 - 因此,每当您想要创建新用户时,只需执行nextID = counter.incr(); newKey = "prefix_" + nextID或类似操作即可。 - DaveR
我明白了,你能把那个加到你的回答里吗?谢谢。现在这样更有意义了。 - majidarif

1
这是一个函数,每次调用它都会返回一个唯一的标识符。只要项目数量不超过32位整数的范围,就应该没问题,这似乎是描述要求的情况。 (警告:一旦UID数组填满,就会进入无限循环。您可能还想创建某种重置函数,可以清空数组并在必要时重置UID。)
var getUID = (function() {
    var UIDs = [];

    return function() {
        var uid;

        do {
            uid = Math.random() * Math.pow(2, 32) | 0x0;
        } while (UIDs[uid] !== undefined);

        return UIDs[uid] = uid;
    };
}());

当应用程序重新启动时,这样做不会忘记ID吗? - majidarif
如果你将 1 << 31 更改为负数,请注意 uid = Math.random() * (-1 >>> 0) | 0。此外,UIDs 应该最初是 {},而不是 [];当长度不准确时,更新 length 是浪费的。 - Ry-
@minitech 我改成了1 << 31,因为我意识到这只会得到31个有效位。不过,还是谢谢你的建议。 - The Paramagnetic Croissant
@ majidarif 实际上,任何 JavaScript 解决方案都可以。然而,这很容易通过在应用程序启动时预填充数组中的 ID 来解决。 - The Paramagnetic Croissant

0
如果你使用"用户"作为键调用这个插入方法,那么你的docId将会自动递增,如下所示: user_0 user_1 user_2 等等...
请注意,Couchbase将在你的桶中显示一个额外的行,其键为meta id,其下一个计数器值为doc值。如果你使用像select count(*) total from table;这样的查询,它将比实际数量多出一行,为了避免这种情况,请使用where子句使该行不被计算在内。
public insert(data: any, key: string) {
  return new Promise((resolve, reject) => {
    let bucket = CouchbaseConnectionManager.getBucket(`${process.env.COUCHBASE_BUCKET}`)
    bucket.counter(key, 1, {initial:0}, (err:any, res:any)=>{
      if(err){
        this.responseHandler(err, res, reject, resolve);
      }
      const docId = key + "_" + res.value;
      bucket.insert(docId, data, (error:any, result:any) => {
        this.responseHandler(error, result, reject, resolve);
      });
    });
  });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接