`
lobbychmd
  • 浏览: 8861 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
文章分类
社区版块
存档分类

mongoDB in action (3) 数据类型(翻译)

阅读更多

数据类型


基本数据类型

.monbodb里面的文档可以理解为json 类似的对象。json格式简单,只支持6种数据类型。很多时候这是好事,容易被理解,解析和记忆。但是,json 的表达能力是有限的。因为只支持 nullbooleannumericstringarray object 这几种类型。

 


尽管这些类型的通常场合足够表达了。但是还是存在其它很多的数据类型,尤其是数据库。例如json 没有 日期类型,对日期的处理要烦恼一些。它有数字类型,但没办法区分浮点和整形。更不用说严格区分32位和64位了。正则表达式和函数类型也没办法表现。

 

monbodb采取了json 的键值对的同时,还支持很多额外的数据类型。虽然不同的语言支持的类型有所不同,但还是有很多共同类型的:

 

null

Null代表空值和不存在的值

{"x" : null}

 

boolean

只有 true false

{"x" : true}

 

32-bit integer

Shell分不出来,一概认为是64位的。会自动转换

64-bit integer

Again, the shell cannot represent these. The shell will display them using a special embedded  document; see the section “Numbers” on page 18 for details.

64-bit floating point number

Shell里面所有数字都认为是这个类型:

{"x" : 3.14}

 

这个也是

{"x" : 3}

 

string

任意 UTF-8 字符:


  

symbol


{"x" : "foobar"}


Shell不支持,会转化为string

object id

唯一的12ID. 

{"x" : ObjectId()}


 

date


 

实际保存为从世纪开始到现在的毫秒数,不支持时区:

{"x" : new Date()}


 

regular expression

采用js 的正则表达式语法

{"x" : /foobar/i}

 

code

可以包含js代码

{"x" : function() { /* ... */ }}

 

binary data

二进制. shell不能处理

maximum value

BSON 包含一个特殊类型来表示可能的最大值。Shell不支持.

minimum  value

BSON 包含一个特殊类型来表示可能的最小值。Shell不支持.

undefined

Undefined 也可以在document里面用(js表示undefinednull 是不一样的):

{"x" : undefined}

 

array

列表:

{"x" : ["a", "b", "c"]}

 

embedded document

嵌套的文档:

{"x" : {"foo" : "bar"}}


Numbers

JS 有一个number 的类型。因为mongodb 3个数字类型(4字节整数、8字节整数、8字节浮点)shell 里面的数字都会默认当作浮点数。这意味着如果你从数据库取出一个4字节整数,然后存进去,即使没有改变它,也会变成了8字节浮点数。因此通常不要把整个document覆盖到mongodb里面去比较好。

另外的一个问题是,一个8字节的整数是不能用8字节的浮点数来表示的。因此如果你保存一个8字节整数然后在shell里面查看它,shell 将会显示为一个嵌套的document来精确的描述它,例如如果我们在document 里面讲myInteger 这个key 的值保存为一个64位的整数,3,然后在shell 里面查看,将会这样显示:

> doc = db.nums.findOne()

{

"_id" : ObjectId("4c0beecfd096a2580fe6fa08"), "myInteger" : {

"floatApprox" : 3

}

}

 

这个数字在数据库里面不会改变(除非你用shell重新保存了一次,这样会转化为浮点);这个嵌套的文档只是用shell显示一个8字节的整数的浮点近似值。这个嵌套文档只有一个key

如果你插入一个不能用浮点来精确表示的8字节整数:shell会加上2keyto bottom,分别代表高位和低位的32位值。例如9223372036854775807会如下显示

> db.nums.findOne()

{

"_id" : ObjectId("4c0beecfd096a2580fe6fa09"), "myInteger" : {

"floatApprox" : 9223372036854776000, "top" : 2147483647,

"bottom" : 4294967295

}

}

The "floatApprox" embedded  documents are special and can be manipulated as num- bers as well as documents:

> doc.myInteger + 1

4


> doc.myInteger.floatApprox

3

 

所有4字节整数可以用8字节浮点数表示,因此正常显示。.

 

Dates

js里面,Date 对象用来表示MongoDB 的日期类型。创建日期对象要用 new Date(),而不是用Date(),后者只是返回一个字符串,并不是一个Date的对象。这不是MonboDB 的问题,而是js就是这样的。如果你不注意就会弄混字符串和日期类型。在删除更新查询的时候造成问题。


shell 里面用本地区域设置来显示日期。但在数据库里面只是记录从纪元开始到现在所过去的毫秒数。所以并没有区域设置保存进去。(当然你可以用另外的key 来保存)

 

Arrays

数组是一组值可以进行有序处理,类似列表,堆栈,队列,或者无序处理,类似集合。.

 

{"things" : ["pie", 3.14]}

 

这里看到数组里面的成员类型是允许不一样的。其实可以是任意的类型,包括嵌套的数组都可以。.

 

.MongoDB 的好处是,它理解数组里面的结构并知道怎么进入内部执行操作。这让我们可以进行查询操作和索引操作,上例,monboDB可以查询所有文档找出things包括3.14,也可以为things建立索引以提高查询速度。

 

MongoDB还允许数组内部元素的原子更新,例如把pie改为pi.  


Embedded Documents

嵌套文档就是将一个key 的值表示为另外一个文档。这样可以让document 看起来比一个平面的结构更自然些.

例如,如果我们有一个文档表示一个人并保存它的地址,就可以嵌套表示为:

{

"name" : "John Doe", "address" : {

"street" : "123 Park Street", "city" : "Anytown",

"state" : "NY"

}

}

 

跟数组一样,mongoDB也理解嵌套文档的结构,可以进行内部的查询和更新.

 

晚点我们会深入讨论schema设计模式。但从这个简单例子,我们也可以了解嵌套文档改变了我们处理数据的方式。传统数据库中这两个信息将会存放在两个表的两条记录中但mongoDB可以用一个文档来表示,如果合理使用嵌套文档可以提供更加自然的信息表示(通常也更有效率).

 

从负面看这种方式不是那么的正规,造成了数据冗余,假设一个地址两个人使用那么关系数据库里面可以用一条记录表示,通过join来关联,但mongoDB只能分别存放,分别更新。

 

_id and ObjectIds

所有文档必须具有_id 键。值类型可以任意的,但通常是ObjectID。一个集合里面,文档的_id 是唯一的。但如果是两个集合,他们之间的文档ID 就可以重复。


ObjectIds

.ObjectID _id的缺省类型。轻量设计,可以在不同的服务器很容易产生一个唯一值。这就是为什么mongodb 用它而不用传统的id 例如自增ID 的原因。自增ID 很难在不同的服务器同步。因为mongodb一开始就设计为一个分布式的数据库,处理很多节点是重要的考虑事项。

 

ObjectID 12字节存储,可以表示为2416进制数字形成的字符串:每个字节2个数字。因此看起来很长,让很多人觉得困惑。其实是存储长度 2倍。

 

如果很快的产生大量的ObjectID,会发现每次只有2个数字改变,通常中部的2个数字改变。这是ObjectID创建的方式。12个字节的规划为下图

 

0     1      2      3      4      5      6      7      8      9      10      11

Timestamp                 Machine             PID           Increment

 

前面四个字节是自纪元开始秒数,这就提供了几个有用的属性。

 

The timestamp, when combined  with the next five bytes (which will be described in a moment), provides uniqueness  at the granularity of a second.

因为时间放前面,因此ObjectID 大体上是按照插入的顺序排列的。虽然并不绝对保证,This is not a strong guarantee but does have some nice properties, such as making ObjectIds efficient to index.

因此,大多数驱动提供一个方法,来从ObjectID获取创建时间的信息。

有人可能会担心是否需要几台服务器同步时间,这是不必要的担心。

接下来3位跟机器相关,通常是取主机名的hash值。这就避免了多台服务器的id 冲突.


接下来的两位跟进程相关,可以保证同一个机器的不同进程产生相同ID

 

前面9位保证多个服务器不同进程在不同的秒产生不同的ID,最后3个字节是一秒当中的流水,最大可以保证产生 2563 (16,777,216)个唯一id

 

自动产生ID

前面说过,如果插入的时候 _id 没有值,那么服务器会产生一个。这个可以由服务器处理,但一般是client 端处理比较好。因为:

A虽然ObjectID的设计是很轻量的,容易产生,但还是有一些开销。在客户端产生ID 实际上也反映了monboDb的哲学。尽量让客户端多做一些事情。虽然Monbodb 是可扩展的系统,但扩展应用程序总是比扩展db来的有效率。

有利客户端的api 设计。假设在服务器端产生id,那么一个插入的api 还需要另外从服务器查询一次才能得到插入文档的Id

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics