前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MongoDB 自增 id 的生成

MongoDB 自增 id 的生成

作者头像
用户3147702
发布2022-06-27 12:57:44
8K0
发布2022-06-27 12:57:44
举报
文章被收录于专栏:小脑斧科技博客

1. 概述

我们使用 MySQL 等关系型数据库时,主键都是设置成自增的。 但在分布式环境下,尤其是在分库分表以后,单纯的自增主键会产生冲突,需要考虑如何生成唯一 ID。 这一点上,mongodb 预先考虑到并采取措施保证了分布式环境中生成的 id 的唯一性。 那么,mongodb 是如何做的呢?这么做有什么好处,又有什么不足呢?本文我们就来介绍一下。

2. MongoDB 中 _id 的生成

mongodb 采用了一个称之为 ObjectId 的类型来做主键,ObjectId 是一个12字节的 BSON 类型字符串,如下图所示。

前9个字节就保证了同一秒钟不同机器不同进程产生的 ObjectId 是唯一的。 而最后三个字节则在每一个进程中通过生成随机数,并以此为基础自增,确保相同进程的同一秒产生的ID也是不同的。 每个进程一秒钟可以最多拥有 256^3(16777216)个不同的 ObjectId 而不会产生冲突。

与此同时,在 _id 中已经保存了时间信息,让我们可以轻易的获取到文档首次插入的时间:

代码语言:javascript
复制
> objid = new ObjectId() 
> ObjectId("53102b43bf1044ed8b0ba36b") 
> objid.getTimestamp() 
> ISODate("2014-02-28T06:22:59Z")

而另一方面,由于时间戳信息被保存在前 3 个字节中,这使得默认排序下,文档数据可以很容易按照插入顺序排序。

3. MongoDB 的哲学

这样设计的主键 ID 从根本上保证了其唯一性,也因此可以不必由 MongoDB 服务器生成,通常,主键 _id 的生成都是由客户端的驱动程序完成的。 这个做法很好的体现了MongoDB的哲学:能交给客户端驱动程序来做的事情就不要交给服务器来做。 我们知道,扩展数据服务应用层也要比扩展数据库层容易得多,这样的设计和实现,很大程度上减轻了数据库扩展的负担。

4. 缺点

虽然在同一个进程内的一秒内生成的多个主键 id 是自增的,但是在数据库全局是没有这样的规律的。 有时,能够完全自增的 id 对于应用业务来说是非常重要的。 同时,’53102b43bf1044ed8b0ba36b’ 这样的字符串对于我们来说也非常不直观,更不用说读写和记忆了。 MongoDB 允许我们自己生成 _id,但是这样唯一性的压力就又来了,在并发环境下保证自增 ID 的严格自增与避免 ID 冲突有时是需要丰富的经验的。

5. 自己生成自增 id — findAndModify

虽然已经有很多生成自增 id 的方案可供选用,如依赖 redis 等,但 MongoDB 本身提供了原子操作,我们可以通过 MongoDB 提供的原子操作来实现 id 的自增。 MongoDB 的 findAndModify 命令可以指定将获取某个键并同时进行某个操作,比如增加操作,从而实现某个字段的自增。 当然,findAndModify 命令是非常强大的,他提供了原子的增删改查操作,本文仅对其自增的方法进行讲解,其他操作较为类似。

5.1. 创建 collection

我们先创建一个自动增长 id 的集合:

代码语言:javascript
复制
> db.ids.save({name:"user", id:0});
> db.ids.find();
{ "_id" : ObjectId("4c637dbd900f00000000686c"), "name" : "user", "id" : 0 }

5.2. 获取自增 id

通过下面的命令就可以获取自增 ID 了。

代码语言:javascript
复制
> userid = db.ids.findAndModify({update:{$inc:{'id':1}}, query:{"name":"user"}, new:true});
{ "_id" : ObjectId("4c637dbd900f00000000686c"), "name" : "user", "id" : 1 }

6. 通过 php 生成 MongoDB 自增 id

代码语言:javascript
复制
<?php
function mid($name, $db){
    $update = array('$inc'=>array("id"=>1));
    $query = array('name'=>$name);
    $command = array(
        'findandmodify'=>'ids', 'update'=>$update,
        'query'=>$query, 'new'=>true, 'upsert'=>true
    );
    $id = $db->command($command);
    return $id['value']['id'];
}

$conn = new Mongo();
$db = $conn->idtest;
$id = mid('user', $db);
$db->user->save(array('uid'=>$id, 'username'=>'techlog', 'password'=>'techlog', 'info'=>'http://techlog.cn'));
$conn->close();
?>

7. 通过 python 生成 MongoDB 自增 id

代码语言:javascript
复制
import pymongo

client = pymongo.MongoClient()
db = client.techlogdb
if db.ids.find_one({'name' : 'user'}) is None:
    db.ids.save({'name' : 'user', 'id' : 0})

result = db.ids.find_and_modify(
    query={'name': 'user'},
    fields={'id': 1, '_id': 0},
    update={'$inc': {'id' : 1}},
    new=True
)
increment_id = result['id']

8. 参考资料

https://www.tutorialspoint.com/mongodb/mongodb_autoincrement_sequence.htm。 https://stackoverflow.com/questions/19524725/how-to-autoincrement-id-at-every-insert-in-pymongo。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. MongoDB 中 _id 的生成
  • 3. MongoDB 的哲学
  • 4. 缺点
  • 5. 自己生成自增 id — findAndModify
    • 5.1. 创建 collection
      • 5.2. 获取自增 id
      • 6. 通过 php 生成 MongoDB 自增 id
      • 7. 通过 python 生成 MongoDB 自增 id
      • 8. 参考资料
      相关产品与服务
      云数据库 MongoDB
      腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档