如何在 Swift 中生成 Mongo DB ObjectID?
How do I generate a Mongo DB ObjectID in Swift?
我需要在 Swift 中生成一个带时间戳的 BSON 格式的对象 ID。 ObjectID 用于 Mongo 数据库。如何实现?
一个天真的解决方案如下所示:
func objectId() -> String {
let time = String(Int(Date().timeIntervalSince1970), radix: 16, uppercase: false)
let machine = String(Int.random(in: 100000 ..< 999999))
let pid = String(Int.random(in: 1000 ..< 9999))
let counter = String(Int.random(in: 100000 ..< 999999))
return time + machine + pid + counter
}
MongoDB docs 指定以下关于ObjectID
- 表示自 Unix 纪元以来的秒数的 4 字节值
- 一个 3 字节的机器标识符
- 一个 2 字节的进程 ID
- 一个 3 字节的计数器,以一个随机值开始
以上将满足该要求。但是,它只会为时间戳以外的部分生成随机数字字符。一个完美的解决方案是为机器和 pid 使用诸如 NSProcessInfo
和 NSUUID
之类的 api。它还必须跟踪计数器。
根据 MongoDB 文档,ObjectId 是使用以下方法生成的:
- 一个 4 字节的时间戳值,表示 ObjectId 的创建,以自 Unix 纪元以来的秒数为单位
- 一个 5 字节的随机值
- 一个 3 字节递增计数器,初始化为一个随机值
您可以使用此 class,它实现了上述内容。
class ObjectId {
private init() {}
static let shared = ObjectId()
private var counter = Int.random(in: 0...0xffffff)
private func incrementCounter() {
if (counter >= 0xffffff) {
counter = 0
} else {
counter += 1
}
}
func generate() -> String {
let time = ~(~Int(NSDate().timeIntervalSince1970))
let random = Int.random(in: 0...0xffffffffff)
let i = counter
incrementCounter()
var byteArray = Array<UInt8>.init(repeating: 0, count: 12)
byteArray[0] = UInt8((time >> 24) & 0xff)
byteArray[1] = UInt8((time >> 16) & 0xff)
byteArray[2] = UInt8((time >> 8) & 0xff)
byteArray[3] = UInt8(time & 0xff)
byteArray[4] = UInt8((random >> 32) & 0xff)
byteArray[5] = UInt8((random >> 24) & 0xff)
byteArray[6] = UInt8((random >> 16) & 0xff)
byteArray[7] = UInt8((random >> 8) & 0xff)
byteArray[8] = UInt8(random & 0xff)
byteArray[9] = UInt8((i >> 16) & 0xff)
byteArray[10] = UInt8((i >> 8) & 0xff)
byteArray[11] = UInt8(i & 0xff)
let id = byteArray
.map({ String([=10=], radix: 16, uppercase: false)
.padding(toLength: 2, withPad: "0", startingAt: 0) })
.joined()
return id
}
}
以下代码将生成一个新的 ObjectId 字符串:
ObjectId.shared.generate()
我需要在 Swift 中生成一个带时间戳的 BSON 格式的对象 ID。 ObjectID 用于 Mongo 数据库。如何实现?
一个天真的解决方案如下所示:
func objectId() -> String {
let time = String(Int(Date().timeIntervalSince1970), radix: 16, uppercase: false)
let machine = String(Int.random(in: 100000 ..< 999999))
let pid = String(Int.random(in: 1000 ..< 9999))
let counter = String(Int.random(in: 100000 ..< 999999))
return time + machine + pid + counter
}
MongoDB docs 指定以下关于ObjectID
- 表示自 Unix 纪元以来的秒数的 4 字节值
- 一个 3 字节的机器标识符
- 一个 2 字节的进程 ID
- 一个 3 字节的计数器,以一个随机值开始
以上将满足该要求。但是,它只会为时间戳以外的部分生成随机数字字符。一个完美的解决方案是为机器和 pid 使用诸如 NSProcessInfo
和 NSUUID
之类的 api。它还必须跟踪计数器。
根据 MongoDB 文档,ObjectId 是使用以下方法生成的:
- 一个 4 字节的时间戳值,表示 ObjectId 的创建,以自 Unix 纪元以来的秒数为单位
- 一个 5 字节的随机值
- 一个 3 字节递增计数器,初始化为一个随机值
您可以使用此 class,它实现了上述内容。
class ObjectId {
private init() {}
static let shared = ObjectId()
private var counter = Int.random(in: 0...0xffffff)
private func incrementCounter() {
if (counter >= 0xffffff) {
counter = 0
} else {
counter += 1
}
}
func generate() -> String {
let time = ~(~Int(NSDate().timeIntervalSince1970))
let random = Int.random(in: 0...0xffffffffff)
let i = counter
incrementCounter()
var byteArray = Array<UInt8>.init(repeating: 0, count: 12)
byteArray[0] = UInt8((time >> 24) & 0xff)
byteArray[1] = UInt8((time >> 16) & 0xff)
byteArray[2] = UInt8((time >> 8) & 0xff)
byteArray[3] = UInt8(time & 0xff)
byteArray[4] = UInt8((random >> 32) & 0xff)
byteArray[5] = UInt8((random >> 24) & 0xff)
byteArray[6] = UInt8((random >> 16) & 0xff)
byteArray[7] = UInt8((random >> 8) & 0xff)
byteArray[8] = UInt8(random & 0xff)
byteArray[9] = UInt8((i >> 16) & 0xff)
byteArray[10] = UInt8((i >> 8) & 0xff)
byteArray[11] = UInt8(i & 0xff)
let id = byteArray
.map({ String([=10=], radix: 16, uppercase: false)
.padding(toLength: 2, withPad: "0", startingAt: 0) })
.joined()
return id
}
}
以下代码将生成一个新的 ObjectId 字符串:
ObjectId.shared.generate()