关于C#生成MongoDB中ObjectId的实现方法

ObjectId介绍
在MongoDB中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键。这个_id默认使用ObjectId来定义,因为ObjectId定义的足够短小,并尽最大可能的保持唯一性,同时能被快速的生成。

ObjectId 是一个 12 Bytes 的 BSON 类型,其包含
1.4 Bytes 自纪元时间开始的秒数
2.3 Bytes 机器描述符
3.2 Bytes 进程ID
4.3 Bytes 随机数

从定义可以看出,在同一秒内,在不同的机器上相同进程ID条件下,非常有可能生成相同的ObjectId。
同时可以根据定义判断出,在给定条件下,ObjectId本身即可描述生成的时间顺序

ObjectId的存储使用Byte数组,而其展现需将Byte数组转换成字符串进行显示,所以通常我们看到的ObjectId都类似于:

ObjectId("507f191e810c19729de860ea")

C#定义ObjectId类


代码如下:

View Code
   public class ObjectId
   {
     private string _string;

public ObjectId()
     {
     }

public ObjectId(string value)
       : this(DecodeHex(value))
     {
     }

internal ObjectId(byte[] value)
     {
       Value = value;
     }

public static ObjectId Empty
     {
       get { return new ObjectId("000000000000000000000000"); }
     }

public byte[] Value { get; private set; }

public static ObjectId NewObjectId()
     {
       return new ObjectId { Value = ObjectIdGenerator.Generate() };
     }

public static bool TryParse(string value, out ObjectId objectId)
     {
       objectId = Empty;
       if (value == null || value.Length != 24)
       {
         return false;
       }

try
       {
         objectId = new ObjectId(value);
         return true;
       }
       catch (FormatException)
       {
         return false;
       }
     }

protected static byte[] DecodeHex(string value)
     {
       if (string.IsNullOrEmpty(value))
         throw new ArgumentNullException("value");

var chars = value.ToCharArray();
       var numberChars = chars.Length;
       var bytes = new byte[numberChars / 2];

for (var i = 0; i < numberChars; i += 2)
       {
         bytes[i / 2] = Convert.ToByte(new string(chars, i, 2), 16);
       }

return bytes;
     }

public override int GetHashCode()
     {
       return Value != null ? ToString().GetHashCode() : 0;
     }

public override string ToString()
     {
       if (_string == null && Value != null)
       {
         _string = BitConverter.ToString(Value)
           .Replace("-", string.Empty)
           .ToLowerInvariant();
       }

return _string;
     }

public override bool Equals(object obj)
     {
       var other = obj as ObjectId;
       return Equals(other);
     }

public bool Equals(ObjectId other)
     {
       return other != null && ToString() == other.ToString();
     }

public static implicit operator string(ObjectId objectId)
     {
       return objectId == null ? null : objectId.ToString();
     }

public static implicit operator ObjectId(string value)
     {
       return new ObjectId(value);
     }

public static bool operator ==(ObjectId left, ObjectId right)
     {
       if (ReferenceEquals(left, right))
       {
         return true;
       }

if (((object)left == null) || ((object)right == null))
       {
         return false;
       }

return left.Equals(right);
     }

public static bool operator !=(ObjectId left, ObjectId right)
     {
       return !(left == right);
     }
   }

C#实现ObjectId的生成器


代码如下:

View Code
   internal static class ObjectIdGenerator
   {
     private static readonly DateTime Epoch =
       new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
     private static readonly object _innerLock = new object();
     private static int _counter;
     private static readonly byte[] _machineHash = GenerateHostHash();
     private static readonly byte[] _processId =
       BitConverter.GetBytes(GenerateProcessId());

public static byte[] Generate()
     {
       var oid = new byte[12];
       var copyidx = 0;

Array.Copy(BitConverter.GetBytes(GenerateTime()), 0, oid, copyidx, 4);
       copyidx += 4;

Array.Copy(_machineHash, 0, oid, copyidx, 3);
       copyidx += 3;

Array.Copy(_processId, 0, oid, copyidx, 2);
       copyidx += 2;

Array.Copy(BitConverter.GetBytes(GenerateCounter()), 0, oid, copyidx, 3);

return oid;
     }

private static int GenerateTime()
     {
       var now = DateTime.UtcNow;
       var nowtime = new DateTime(Epoch.Year, Epoch.Month, Epoch.Day,
         now.Hour, now.Minute, now.Second, now.Millisecond);
       var diff = nowtime - Epoch;
       return Convert.ToInt32(Math.Floor(diff.TotalMilliseconds));
     }

private static byte[] GenerateHostHash()
     {
       using (var md5 = MD5.Create())
       {
         var host = Dns.GetHostName();
         return md5.ComputeHash(Encoding.Default.GetBytes(host));
       }
     }

private static int GenerateProcessId()
     {
       var process = Process.GetCurrentProcess();
       return process.Id;
     }

private static int GenerateCounter()
     {
       lock (_innerLock)
       {
         return _counter++;
       }
     }
   }

使用举例


代码如下:

class Program
   {
     static void Main(string[] args)
     {
       Console.ForegroundColor = ConsoleColor.Red;

ObjectId emptyOid = ObjectId.Empty;
       Console.WriteLine(emptyOid);

Console.WriteLine();
       Console.ForegroundColor = ConsoleColor.Green;

for (int i = 0; i < 10; i++)
       {
         ObjectId oid = ObjectId.NewObjectId();
         Console.WriteLine(oid);
       }

Console.WriteLine();
       Console.ForegroundColor = ConsoleColor.Blue;

ObjectId existingOid;
       ObjectId.TryParse("507f191e810c19729de860ea", out existingOid);
       Console.WriteLine(existingOid);

Console.ReadKey();
     }
   }

(0)

相关推荐

  • 深究从MongoDB的ObjectId中获取时间信息

    MongoDB默认使用_id字段作为主键,类型为ObjectId.ObjectId的生成有一定的规则,详情可以查看这篇文章 - MongoDB深究之ObjectId.如果你在写入数据库的时候忘记写入创建时间,不用担心,完全可以通过_id字段的值来还原当时的时间.看下面的mongodb script脚本: db.getCollection('fees').find({}).forEach(function(item){ var _str = item._id.toString().substr(1

  • python根据时间生成mongodb的ObjectId的方法

    本文实例讲述了python根据时间生成mongodb的ObjectId的方法.分享给大家供大家参考.具体分析如下: mongodb的_id为ObjectId类型,ObjectId内是包含时间戳信息的,这样我们在保存数据的时候就不需要再单独记录一个添加时间了,如果需要按照时间查询,我们可以先把时间变化成可查询的ObjectId,再通过_id字段查询,由于mongodb的_id是主键,查询效率非常高.下面的函数给出了如何把时间换算成ObjectId,同时该函数还可以指定时间的偏移量,比如多少天前的时

  • MongoDB中ObjectId的误区及引起的一系列问题

    近期对两个应用进行改造,在上线过程中出现一系列问题(其中一部分是由于ObjectId误区导致的) 先来了解下ObjectId: TimeStamp 前 4位是一个unix的时间戳,是一个int类别,我们将上面的例子中的objectid的前4位进行提取"4df2dcec",然后再将他们安装十六进制 专为十进制:"1307761900",这个数字就是一个时间戳,为了让效果更佳明显,我们将这个时间戳转换成我们习惯的时间格式(精确到秒) $ date -d '1970-01

  • python将MongoDB里的ObjectId转换为时间戳的方法

    本文实例讲述了python将MongoDB里的ObjectId转换为时间戳的方法.分享给大家供大家参考.具体分析如下: MongoDB里的_id字段前四位是时间戳的16进制表示,通过Python可以很容易从_id中提取出时间戳来 def timestamp_from_objectid(objectid): result = 0 try: result = time.mktime(objectid.generation_time.timetuple()) except: pass return r

  • java查询mongodb中的objectid示例

    找了很久查询objectid的方法都是错的,用mongovue能查询出来,但就是用java不知道怎么查询 1.mongovue里的查询方式: 复制代码 代码如下: {"_id" : ObjectId("5326bfc0e6f780b21635248f")} 2.纯mongodb里的查询方式: 复制代码 代码如下: db.collect.find({ "_id" : ObjectId("5326bfc0e6f780b21635248f&q

  • 关于C#生成MongoDB中ObjectId的实现方法

    ObjectId介绍在MongoDB中,文档(document)在集合(collection)中的存储需要一个唯一的_id字段作为主键.这个_id默认使用ObjectId来定义,因为ObjectId定义的足够短小,并尽最大可能的保持唯一性,同时能被快速的生成. ObjectId 是一个 12 Bytes 的 BSON 类型,其包含:1.4 Bytes 自纪元时间开始的秒数2.3 Bytes 机器描述符3.2 Bytes 进程ID4.3 Bytes 随机数 从定义可以看出,在同一秒内,在不同的机器

  • MongoDB中数据的替换方法实现类Replace()函数功能详解

    近日接到一个开发需求,因业务调整,需要DBA协助,将MongoDB数据库中某集合的进行替换.例如我们需要将集合A中B字段中,有关<美好>的字符替换为 <非常美好>.个人感觉这个需求如果是在SQL Server 或MySQL 数据库上处理是小菜一碟,如果是针对MongoDB数据,可能要费神了. 1.常见关系数据数据库中的替换函数 在SQL Server数据库中,我们用Replace函数来实现字符的替换. 语法 REPLACE ( ''string_replace1'' , ''str

  • MongoDB中MapReduce的使用方法详解

    前言 玩过Hadoop的小伙伴对MapReduce应该不陌生,MapReduce的强大且灵活,它可以将一个大问题拆分为多个小问题,将各个小问题发送到不同的机器上去处理,所有的机器都完成计算后,再将计算结果合并为一个完整的解决方案,这就是所谓的分布式计算.本文我们就来看看MongoDB中MapReduce的使用. 打算用mongodb mapreduce之前一定要知道的事!!! mapreduce其实是分批处理数据的,每一百次重新reduce处理,所以到reduce里的数据如果是101条,那就会分

  • PHP库 查询Mongodb中的文档ID的方法

    在IBM我的一份新工作是一名开发的后勤人员.那意味着我的大部分时间是在和数据库打交道.在我的工作流程中,我花了一些时间在MongoDB上面--这是一个文档数据库.但是在通过ID来检索记录这个操作上面我碰到了一些问题.下面的代码是最终版本,以后碰到类似的问题我可以直接引用它.如果大家也需要,希望下面对大家有所帮助. MongoDB 和 IDs 当我向一个集合中插入数据的时候,我并没有设置_id字段:如果这个字段是空的话,那么MongoDB将要自动生成一个ID来使用,这对我来说是非常不错的.然而,当

  • MongoDB中强大的统计框架Aggregation使用实例解析

    听说项目里面Aggregation用的多,那就专门针对这个多多练习一下. 基本的操作包括: •$project - 可以从子文档中提取字段,可以重命名字段 •$match - 可以实现查找的功能 •$limit - 接受一个数字n,返回结果集中的前n个文档. •$skip - 接受一个数字n,丢弃结果集中的前n个文档.效率比较低,依然会遍历前n个文档. •$unwind - 可以将一个包含数组的文档切分成多个, 比如你的文档有 中有个数组字段 A, A中有10个元素, 那么经过 $unwind处

  • Node.js使用MongoDB的ObjectId作为查询条件的方法

    当往MongoDB中插入一条数据时,会自动生成ObjectId作为数据的主键. 那么如何通过ObjectId来做数据的唯一查询呢? 在MongoDB中插入一条数据 在MongoDB中插入一条如下结构的数据: { _id: 5d6a32389c825e24106624e4, title: 'GitHub 上有什么好玩的项目', content: '上个月有水友私信问我,GitHub 上有没有比较好玩的项目可以推荐?我跟他说:"有,过两天我整理一下".\n' + '\n' + '然而,一个

  • MongoDB中对文档的增删查改基本操作方法总结

    插入文档:insert() 方法 要插入数据到 MongoDB 集合,需要使用 MongoDB 的  insert() 或 save() 方法. 语法: insert() 命令的基本语法如下: >db.COLLECTION_NAME.insert(document) 例子:  >db.mycol.insert({    _id: ObjectId(7df78ad8902c),    title: 'MongoDB Overview',     description: 'MongoDB is

随机推荐