Go 使用ObjectID
ObjectID介绍
MongoDB中的ObjectId是一种特殊的12字节 BSON 类型数据,用于为主文档提供唯一的标识符,默认情况下作为 _id 字段的默认值出现在每一个MongoDB集合中的文档中。以下是ObjectId的具体组成:
1. 时间戳(Timestamp):
- 前4个字节(32位)表示创建该ObjectId时的Unix时间戳,精确到秒,从1970年1月1日UTC时间零点开始计算,这使得ObjectId具有一定程度的时间有序性。
2. 机器标识符(Machine ID):
- 接下来的3个字节(24位)代表了生成此ObjectId的机器主机的唯一标识符。这个标识符通常是基于主机的网络接口地址哈希得到的,目的是确保不同主机生成的ObjectId是不同的。
3. 进程标识符(PID):
- (旧版描述中提到的是进程ID,但在MongoDB较新版本中已不再使用)在某些早期的描述中提及2个字节代表进程ID,不过实际上MongoDB并不使用进程ID来生成ObjectId,以避免因为PID重用导致的冲突。现在这部分数据通常用于其他目的以保证全局唯一性。
4. 计数器(Counter):
- 最后的3个字节(24位)是一个自增计数器,在同一台机器同一秒内生成的ObjectId会通过这个计数器递增来确保唯一性。计数器在一个秒内是从一个随机数开始递增的,这样即使在同一秒内创建多个ObjectId也能保证在单机上的唯一性。
因此,ObjectId的设计可以确保在分布式的环境下,每个文档都能拥有一个全局唯一的标识符,同时也包含了时间信息,这对于很多应用场景来说非常有用,比如排序、索引和逻辑处理。
ObjectID使用
分布式系统需要全局唯一ID且有序的,可以考虑ObjectID。
UUID太长了,且是无序的。感觉不太好,ObjectID算是个还可以的选择。当然还有很多其它方案。
Go项目,在Mongodb的驱动包里,有一个文件是objectid.go,有写好ObjectID生成算法。如果项目只要一个算法没必要引入完整的包,可以直接把这个文件拷贝出来。
内容如下:
package hobjectidimport ("crypto/rand""encoding""encoding/binary""encoding/hex""encoding/json""errors""fmt""io""sync/atomic""time"
)// 代码来自 https://github.com/mongodb/mongo-go-driver/blob/v1/bson/primitive/objectid.go// ErrInvalidHex indicates that a hex string cannot be converted to an ObjectID.
var ErrInvalidHex = errors.New("the provided hex string is not a valid ObjectID")// ObjectID is the BSON ObjectID type.
type ObjectID [12]byte// NilObjectID is the zero value for ObjectID.
var NilObjectID ObjectIDvar objectIDCounter = readRandomUint32()
var processUnique = processUniqueBytes()var _ encoding.TextMarshaler = ObjectID{}
var _ encoding.TextUnmarshaler = &ObjectID{}// NewObjectID generates a new ObjectID.
func NewObjectID() ObjectID {return NewObjectIDFromTimestamp(time.Now())
}// NewObjectIDFromTimestamp generates a new ObjectID based on the given time.
func NewObjectIDFromTimestamp(timestamp time.Time) ObjectID {var b [12]bytebinary.BigEndian.PutUint32(b[0:4], uint32(timestamp.Unix()))copy(b[4:9], processUnique[:])putUint24(b[9:12], atomic.AddUint32(&objectIDCounter, 1))return b
}// Timestamp extracts the time part of the ObjectId.
func (id ObjectID) Timestamp() time.Time {unixSecs := binary.BigEndian.Uint32(id[0:4])return time.Unix(int64(unixSecs), 0).UTC()
}// Hex returns the hex encoding of the ObjectID as a string.
func (id ObjectID) Hex() string {var buf [24]bytehex.Encode(buf[:], id[:])return string(buf[:])
}func (id ObjectID) String() string {return fmt.Sprintf("ObjectID(%q)", id.Hex())
}// IsZero returns true if id is the empty ObjectID.
func (id ObjectID) IsZero() bool {return id == NilObjectID
}// ObjectIDFromHex creates a new ObjectID from a hex string. It returns an error if the hex string is not a
// valid ObjectID.
func ObjectIDFromHex(s string) (ObjectID, error) {if len(s) != 24 {return NilObjectID, ErrInvalidHex}var oid [12]byte_, err := hex.Decode(oid[:], []byte(s))if err != nil {return NilObjectID, err}return oid, nil
}// IsValidObjectID returns true if the provided hex string represents a valid ObjectID and false if not.
//
// Deprecated: Use ObjectIDFromHex and check the error instead.
func IsValidObjectID(s string) bool {_, err := ObjectIDFromHex(s)return err == nil
}// MarshalText returns the ObjectID as UTF-8-encoded text. Implementing this allows us to use ObjectID
// as a map key when marshalling JSON. See https://pkg.go.dev/encoding#TextMarshaler
func (id ObjectID) MarshalText() ([]byte, error) {return []byte(id.Hex()), nil
}// UnmarshalText populates the byte slice with the ObjectID. Implementing this allows us to use ObjectID
// as a map key when unmarshalling JSON. See https://pkg.go.dev/encoding#TextUnmarshaler
func (id *ObjectID) UnmarshalText(b []byte) error {oid, err := ObjectIDFromHex(string(b))if err != nil {return err}*id = oidreturn nil
}// MarshalJSON returns the ObjectID as a string
func (id ObjectID) MarshalJSON() ([]byte, error) {return json.Marshal(id.Hex())
}// UnmarshalJSON populates the byte slice with the ObjectID. If the byte slice is 24 bytes long, it
// will be populated with the hex representation of the ObjectID. If the byte slice is twelve bytes
// long, it will be populated with the BSON representation of the ObjectID. This method also accepts empty strings and
// decodes them as NilObjectID. For any other inputs, an error will be returned.
func (id *ObjectID) UnmarshalJSON(b []byte) error {// Ignore "null" to keep parity with the standard library. Decoding a JSON null into a non-pointer ObjectID field// will leave the field unchanged. For pointer values, encoding/json will set the pointer to nil and will not// enter the UnmarshalJSON hook.if string(b) == "null" {return nil}var err errorswitch len(b) {case 12:copy(id[:], b)default:// Extended JSONvar res interface{}err := json.Unmarshal(b, &res)if err != nil {return err}str, ok := res.(string)if !ok {m, ok := res.(map[string]interface{})if !ok {return errors.New("not an extended JSON ObjectID")}oid, ok := m["$oid"]if !ok {return errors.New("not an extended JSON ObjectID")}str, ok = oid.(string)if !ok {return errors.New("not an extended JSON ObjectID")}}// An empty string is not a valid ObjectID, but we treat it as a special value that decodes as NilObjectID.if len(str) == 0 {copy(id[:], NilObjectID[:])return nil}if len(str) != 24 {return fmt.Errorf("cannot unmarshal into an ObjectID, the length must be 24 but it is %d", len(str))}_, err = hex.Decode(id[:], []byte(str))if err != nil {return err}}return err
}func processUniqueBytes() [5]byte {var b [5]byte_, err := io.ReadFull(rand.Reader, b[:])if err != nil {panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))}return b
}func readRandomUint32() uint32 {var b [4]byte_, err := io.ReadFull(rand.Reader, b[:])if err != nil {panic(fmt.Errorf("cannot initialize objectid package with crypto.rand.Reader: %w", err))}return (uint32(b[0]) << 0) | (uint32(b[1]) << 8) | (uint32(b[2]) << 16) | (uint32(b[3]) << 24)
}func putUint24(b []byte, v uint32) {b[0] = byte(v >> 16)b[1] = byte(v >> 8)b[2] = byte(v)
}
使用生成算法,生成的ID 可以与环境无关、业务无关。通用性更好。
相关文章:
Go 使用ObjectID
ObjectID介绍 MongoDB中的ObjectId是一种特殊的12字节 BSON 类型数据,用于为主文档提供唯一的标识符,默认情况下作为 _id 字段的默认值出现在每一个MongoDB集合中的文档中。以下是ObjectId的具体组成: 1. 时间戳(Timestamp&…...

基于SpringBoot+Vue的疾病防控系统设计与实现(源码+文档+包运行)
一.系统概述 在如今社会上,关于信息上面的处理,没有任何一个企业或者个人会忽视,如何让信息急速传递,并且归档储存查询,采用之前的纸张记录模式已经不符合当前使用要求了。所以,对疾病防控信息管理的提升&a…...

2024年阿里云4核8G配置云服务器价格低性能高!
阿里云4核8G服务器租用优惠价格700元1年,配置为ECS通用算力型u1实例(ecs.u1-c1m2.xlarge)4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选,CPU采用Intel(R) Xeon(R) Platinum处理器,阿里云优惠 aliyunfuwuqi…...
关于ContentProvider这一遍就够了
ContentProvider是什么? ContentProvider是Android四大组件之一,主要用于不同应用程序之间或者同一个应用程序的不同部分之间共享数据。它是Android系统中用于存储和检索数据的抽象层,允许不同的应用程序通过统一的接口访问数据,…...
《1w实盘and大盘基金预测 day23》
这几天预测错麻了,哈哈哈,完全和技术没关系,全是消息面。 昨日预测: 2958-2984-3010 证券继续下跌,昨天诱多把我诱惑进去了(看2-3天的反弹也没了),今天直接出掉昨天买的。 整体操作…...

向量数据库与图数据库:理解它们的区别
作者:Elastic Platform Team 大数据管理不仅仅是尽可能存储更多的数据。它关乎能够识别有意义的见解、发现隐藏的模式,并做出明智的决策。这种对高级分析的追求一直是数据建模和存储解决方案创新的驱动力,远远超出了传统关系数据库。 这些创…...

WIN7用上最新版Chrome
1.下载WIN10最新版Chrome的离线安装包 谷歌浏览器 Chrome 最新版离线安装包下载地址 v123.0.6312.123 - 每日自动更新 | 异次元软件 文件名称:123.0.6312.123_chrome_installer.exe。 123.0.6312.123_chrome_installer.exe 文件右键解压缩得到 chrome.7z&#x…...

node.jd版本降级/升级
第一步.先清空本地安装的node.js版本 按健winR弹出窗口,键盘输入cmd,然后敲回车(或者鼠标直接点击电脑桌面最左下角的win窗口图标弹出,输入cmd再点击回车键) 进入命令控制行窗口,输入where node,查看本地…...

python+playwright 学习-88 禁止加载图片等资源
前言 对于爬虫的小伙伴来说,有时候只需抓取页面的文本,不用加载图片,可以加快操作页面速度,那么我们可以设置禁止加载图片等资源。 禁止图片加载 根据url地址的后缀,图片资源后缀一般是png,jpg,jpeg,gif等格式。 from playwright.sync_api import sync_playwrightwith…...

Linux:Redis7.2.4的简单在线部署(1)
注意:我写的这个文章是以最快速的办法去搭建一个redis的基础环境,作用是为了做实验简单的练习,如果你想搭建一个相对稳定的redis去使用,可以看我下面这个文章 Linux:Redis7.2.4的源码包部署(2)-…...

HackMyVM-Connection
目录 信息收集 arp nmap WEB web信息收集 dirsearch smbclient put shell 提权 系统信息收集 suid gdb提权 信息收集 arp ┌─[rootparrot]─[~/HackMyVM] └──╼ #arp-scan -l Interface: enp0s3, type: EN10MB, MAC: 08:00:27:16:3d:f8, IPv4: 192.168.9.115 S…...

Prometheus接入AlterManager配置邮件告警(基于K8S环境部署)
目录 一.配置Alertmanager告警发送至邮箱二.Prometheus接入AlertManager三.部署PrometheusAlterManager(放到一个Pod中)四. 测试告警 基于 此环境做实验 一.配置Alertmanager告警发送至邮箱 1.创建AlertManager ConfigMap资源清单 vim alertmanager-cm.yaml --- kind: Confi…...

find方法
find() 方法用于在数组中查找符合条件的第一个元素,并返回该元素。如果找到匹配的元素,则返回该元素的值;如果未找到匹配的元素,则返回 undefined。 例如: const firstWithdrawal movements.find(mov > mov < 0); consol…...

TLS v1.3 导致JetBrains IDE jdk.internal.net.http.common CPU占用高
开发环境 GoLand版本:2022.3.4 问题原因 JDK 中的 TLS v1.3 实现引起 解决办法 使用 SOCKS 代理代替HTTP代理 禁用 Space 和 Code With Me 插件 禁用 TLS v1.3,参考:https://stackoverflow.com/questions/54485755/java-11-httpclient-…...

计算机网络 2.2数据传输方式
第二节 数据传输方式 一、数据通信系统模型 添加图片注释,不超过 140 字(可选) 1.数据终端设备(DTE) 作用:用于处理用户数据的设备,是数据通信系统的信源和信宿。 设备:便携计算机…...

陇剑杯 流量分析 webshell CTF writeup
陇剑杯 流量分析 链接:https://pan.baidu.com/s/1KSSXOVNPC5hu_Mf60uKM2A?pwdhaek 提取码:haek目录结构 LearnCTF ├───LogAnalize │ ├───linux简单日志分析 │ │ linux-log_2.zip │ │ │ ├───misc日志分析 │ │ …...

【测试开发学习历程】python常用的模块(下)
目录 8、MySQL数据库的操作-pymysql 8.1 连接并操作数据库 9、ini文件的操作-configparser 9.1 模块-configparser 9.2 读取ini文件中的内容 9.3 获取指定建的值 10 json文件操作-json 10.1 json文件的格式或者json数据的格式 10.2 json.load/json.loads 10.3 json.du…...
GCDAsynSocket之TCP简析
GCDAsynSocket是一个开源的基于GCD的异步的socket库。它支持IPV4和IPV6地址,TLS/SSL协议。同时它支持iOS端和Mac端。本篇主要介绍一下GCDAsynSocket中的TCP用法和实现。 首先通过下面这个方法初始化一个GCDAsynSocket对象。 - (id)initWithDelegate:(id<GCDAsyn…...

大型网站系统架构演化实例_1.单体架构和垂直架构
大型网站的技术挑战主要来自于庞大的用户,高并发的访问和海量的数据,任何简单的业务一旦需要处理数以P计的数据和面对数以亿计的用户,问题就会变得很棘手。通常大型网站架构主要解决这类问题。 1.第一阶段:单体架构 大型网站都是…...

2024蓝桥杯——宝石问题
先展示题目 声明 以下代码仅是我的个人看法,在自己考试过程中的优化版,本人考试就踩了很多坑,我会—一列举出来。代码可能很多,但是总体时间复杂度不高只有0(N) 函数里面的动态数组我没有写开辟判断和free,这里我忽略…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
快刀集(1): 一刀斩断视频片头广告
一刀流:用一个简单脚本,秒杀视频片头广告,还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农,平时写代码之余看看电影、补补片,是再正常不过的事。 电影嘛,要沉浸,…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
以Module Federation 插件详为例,Webpack.config.js它可能的配置和含义如下: 前言 Module Federation 的Webpack.config.js核心配置包括: name filename(定义应用标识) remotes(引用远程模块࿰…...