MongoDB进步认识

关系

关系型数据库中有1对1、1对多、多对1、多对多关系,MongoDB也一样。
MongoDB用BSON组织数据,这一点要灵活很多。实例:一个人有多个地址。我们可以有两张表来存放,一个user表、一个address表。user和address是一对多关系。
看user表中的一个document

{
   "_id":ObjectId("72355788888abcf289bc9cc4"),
   "name": "sunyang",
   "contact": "12345678",
   "age": "27"
}

对应的address

{
   "_id":ObjectId("52ffc4a5d85242602e000000"),
   "building": "changan road No.123",
   "pincode": 123456,
   "city": "Beijing",
   "state": "China"
} 
嵌入
{
   "_id":ObjectId("72355788888abcf289bc9cc4"),
   "name": "sunyang",
   "contact": "12345678",
   "age": "27",
   "address":[
	{
	   "_id":ObjectId("52ffc4a5d85242602e000000"),
	   "building": "changan road No.123",
	   "pincode": 123456,
	   "city": "Beijing",
	   "state": "China"
	} ,
	{
	   "_id":ObjectId("52ffc4a5d85242602e000001"),
	   "building": "changan road No.123",
	   "pincode": 123456,
	   "city": "Beijing",
	   "state": "China"
	} 
  ]
}

这样数据保存在一个文档中,查询起来很方便

db.users.findOne({"name":"sunyang"},{"address":1})
引用
{
   "_id":ObjectId("72355788888abcf289bc9cc4"),
   "name": "sunyang",
   "contact": "12345678",
   "age": "27",
   "address_ids":[
	   ObjectId("52ffc4a5d85242602e000000"),
	   ObjectId("52ffc4a5d85242602e000001")
  ]
}

这种方式需要两次查询,先查ObjectId,再查地址。

>var result = db.users.findOne({"name":"sunyang"},{"address_ids":1})
>var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
数据库引用

跨数据库引用的场景
需要用到三个参数

{ $ref : , $id : , $db :  }

实例

{
   "_id":ObjectId("1111222222333333333"),
   "address": {
   "$ref": "address_home",
   "$id": ObjectId("11111111111111111111"),
   "$db": "address"},
   "contact": "123456",
   "age": "27",
   "name": "sunyang"
}

查找方式

>var user = db.users.findOne({"name":"sunyang"})
>var dbRef = user.address
>db[dbRef.$ref].findOne({"_id":ObjectId(dbRef.$id)})

这种命名空间类型,明显是在数据库内部维护了一个树形结构,通过类似占位符的形式取值。

索引

语法

db.collection.createIndex(keys, options)

实例

db.col.createIndex({"title":1,"description":-1})
db.values.createIndex({open: 1, close: 1}, {background: true})

1:升序
-1:降序

options包括

background 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 “background” 默认值为false。
unique 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds integer 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
v 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights document 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

查看集合索引

db.col.getIndexes()

查看集合索引大小

db.col.totalIndexSize()

删除集合所有索引

db.col.dropIndexes()

删除集合指定索引

db.col.dropIndex("索引名称")
覆盖查询

这个网上也有很多解释,有一些明显是错误的。这个覆盖索引跟oracle索引一样,会走fast range scan。
举例

>db.users.createIndex({gender:1,user_name:1})

我要按gender搜索user_name,并排除_id值,这时候就直接从索引上取数据。(因为_id会默认返回)

>db.users.find({gender:"M"},{user_name:1,_id:0})

mongodb说,索引是创建在内存中,所以相当于读缓存,会很快。但索引都在内存中不会对内存造成影响吗?
索引字段是个数组不能走覆盖索引。(这个概念是比较新的,因为在oracle、mysql是不可能存在这种情况)

explain()查询分析
>db.users.find({gender:"M"},{user_name:1,_id:0}).explain()

可以查看的字段

indexOnly: 字段为 true ,表示我们使用了索引。
cursor:因为这个查询使用了索引,MongoDB 中索引存储在B树结构中,所以这是也使用了 BtreeCursor 类型的游标。如果没有使用索引,游标的类型是 BasicCursor。这个键还会给出你所使用的索引的名称,你通过这个名称可以查看当前数据库下的system.indexes集合(系统自动创建,由于存储索引信息,这个稍微会提到)来得到索引的详细信息。
n:当前查询返回的文档数量。
nscanned/nscannedObjects:表明当前这次查询一共扫描了集合中多少个文档,我们的目的是,让这个数值和返回文档的数量越接近越好。
millis:当前查询所需时间,毫秒数。
indexBounds:当前查询具体使用的索引。

hint()指定索引

如下查询实例指定了使用 gender 和 user_name 索引字段来查询:

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})
数组索引

考虑如下集合

{
   "address": {
      "city": "Los Angeles",
      "state": "California",
      "pincode": "123"
   },
   "tags": [
      "music",
      "cricket",
      "blogs"
   ],
   "name": "Tom Benzamin"
}

tags字段是一个集合,这里可以看做是用户标签,在这个上建索引,相当于在集合所包含的所有元素上建联合索引。

>db.users.ensureIndex({"tags":1})

使用

>db.users.find({tags:"cricket"})
子文档索引

如何要筛选的条件,在另一个关系表里,比如商品表和商品详情表,首页搜索条件在详情表里,这时候可以在商品表里创建子文档索引。
感觉这种索引有些复杂,在实际开发中可能创建主表索引并关联查询比较好。
实例:

>db.users.ensureIndex({"address.city":1,"address.state":1,"address.pincode":1})

一旦创建索引,我们可以使用子文档的字段来检索数据:

>db.users.find({"address.city":"Los Angeles"})  

和oracle一样,字段位置不影响分析器是否走索引的判断。

索引内存问题

由于索引是存储在内存(RAM)中,你应该确保该索引的大小不超过内存的限制。
如果索引的大小大于内存的限制,MongoDB会删除一些索引,这将导致性能下降。
有些情况不会走索引,这和oracle思想是一样的,比如对字段进行算术运算、正则表达式、$where 子句。(这里好像和oracle有些不同,where条件不走索引,find()方法走索引)

索引大小

集合中索引不能超过64个
索引名的长度不能超过128个字符
一个复合索引最多可以有31个字段

聚合

类似sql中的count(*)

>db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)

聚合的表达式

$sum	计算总和。	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}])
$avg	计算平均值	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}])
$min	获取集合中所有文档对应值得最小值。	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}])
$max	获取集合中所有文档对应值得最大值。	db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}])
$push	在结果文档中插入值到一个数组中。	db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}])
$addToSet	在结果文档中插入值到一个数组中,但不创建副本。	db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}])
$first	根据资源文档的排序获取第一个文档数据。	db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}])
$last	根据资源文档的排序获取最后一个文档数据	db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}])

管道操作

$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。
$match:用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。
$limit:用来限制MongoDB聚合管道返回的文档数。
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
$group:将集合中的文档分组,可用于统计结果。
$sort:将输入文档排序后输出。
$geoNear:输出接近某一地理位置的有序文档。

实例:

db.article.aggregate(
    { $project : {
        title : 1 ,
        author : 1 ,
    }}
 );

这样的话结果中就只还有_id,tilte和author三个字段了,默认情况下_id字段是被包含的,如果要想不包含_id话可以这样:

db.article.aggregate(
    { $project : {
        _id : 0 ,
        title : 1 ,
        author : 1
    }});

$match实例

db.articles.aggregate( [
                        { $match : { score : { $gt : 70, $lte : 90 } } },
                        { $group: { _id: null, count: { $sum: 1 } } }
                       ] );

$ match用于获取分数大于70小于或等于90记录,然后将符合条件的记录送到下一阶段$group管道操作符进行处理。
$skip实例

db.article.aggregate(
    { $skip : 5 });

经过$skip管道操作符处理后,前五个文档被"过滤"掉。(分页)

ObjectId

ObjectId 类似唯一主键,可以很快的去生成和排序,包含 12 bytes,含义是:

前 4 个字节表示创建 unix 时间戳,格林尼治时间 UTC 时间,比北京时间晚了 8 个小时
接下来的 3 个字节是机器标识码
紧接的两个字节由进程 id 组成 PID
最后三个字节是随机数

形式上这个和oracle中的rowid差不多,但是里面保存的信息多。
创建ObjectId

>newObjectId = ObjectId()

从ObjectId中获取时间戳

>ObjectId("5349b4ddd2781d08c09890f4").getTimestamp()

转换成字符串

>new ObjectId().str

注:根据http://www.runoob.com/mongodb/ 整理学习

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值