如何在Swift中生成Mongo DB ObjectID?

时间:2016-04-08 20:08:32

标签: swift bson

我需要在Swift中生成BSON格式的带时间戳的对象ID。 ObjectID适用于Mongo DB。如何实现这一目标?

2 个答案:

答案 0 :(得分:4)

一个天真的解决方案看起来像这样:

func objectId() -> String {
    let time = String(Int(NSDate().timeIntervalSince1970), radix: 16, uppercase: false)
    let machine = String(arc4random_uniform(900000) + 100000)
    let pid = String(arc4random_uniform(9000) + 1000)
    let counter = String(arc4random_uniform(900000) + 100000)
    return time + machine + pid + counter
}

MongoDB docs指定有关ObjectID的以下内容

  • 一个4字节的值,表示自Unix纪元以来的秒数
  • 3字节机器标识符
  • 一个2字节的进程ID
  • 一个3字节的计数器,以随机值
  • 开头

以上将满足该要求。但是,它只会为时间戳以外的部分生成随机数字符。一个完美的解决方案是使用NSProcessInfoNSUUID之类的apis作为机器和pid。它还必须跟踪一个计数器。

答案 1 :(得分:0)

从MongoDB文档中,使用以下方法生成ObjectId:

  • 一个4字节的时间戳记值,代表自Unix时代以来以秒为单位的ObjectId的创建
  • 5字节随机值
  • 3字节递增计数器,已初始化为随机值

您可以使用实现上述内容的此类。

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($0, radix: 16, uppercase: false)
                     .padding(toLength: 2, withPad: "0", startingAt: 0) })
                     .joined()

        return id
    }
}

以下代码将生成一个新的ObjectId字符串:

ObjectId.shared.generate()