NoSql简介
- NoSQL(Not Only SQL ),意即“不仅仅是SQL” ,指的是非关系型的数据库 。是一项全新的数据库革命性运动,早期就有人提出,发展至2009年趋势越发高涨。NoSQL的拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入。
-
关系型数据库中的表都是存储一些结构化的数据,每条记录的字段的组成都一样,即使不是每条记录都需要所有的字段,但数据库会为每条数据分配所有的字段。而非关系型数据库以键值对(key-value)存储,它的结构不固定,每一条记录可以有不一样的键,每条记录可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。
NOSql数据库的优缺点
-
在优势方面主要体现在下面几点:
- 简单的扩展
- 快速的读写
- 低廉的成本
- 灵活的数据模型
-
在不足方面主要有下面几点:
- 不提供对SQL的支持
- 支持的特性不够丰富
- 现有的产品不够成熟
MongoDB简介
MongoDB是用C++语言编写的非关系型数据库。特点是高性能、易部署、易使用,存储数据十分方便,主要特性有:
- 面向集合存储,易于存储对象类型的数据
- 模式自由
- 支持动态查询
- 支持完全索引,包含内部对象
- 支持复制和故障恢复
- 使用高效的二进制数据存储,包括大型对象
- 文件存储格式为BSON(一种JSON的扩展)
MongoDB基本概念
- 文档(document)是MongoDB中数据的基本单元,非常类似于关系型数据库系统中的行(但是比行要复杂的多)
- 集合(collection)就是一组文档,如果说MongoDB中的文档类似于关系型数据库中的行,那么集合就如同表
- MongoDB的单个计算机可以容纳多个独立的数据库,每一个数据库都有自己的集合和权限
- MongoDB自带简洁但功能强大的JavaScript shell,这个工具对于管理MongoDB实例和操作数据作用非常大
- 每一个文档都有一个特殊的键"_id",它在文档所处的集合中是唯一的,相当于关系数据库中的表的主键
数据库基本操作
创建一个数据库
use [databaseName]
注意:使用该命令,你什么也不干就离开的话这个空数据库就会被删除查看所有数据库
show dbs
给指定数据库添加集合并且添加记录
db.[documentName].insert({...})
查看制定文档的数据
show collections
更新文档数据
db.[documentName].update({查询条件},{更新内容})
例:
var p = db.persons.findOne()
db.persons.update(p,{name:"myNewName"})
-
Shell的help
- 里面的所有的shell可以完成命令帮助
- 全局的help
- 数据库相关的
db.help()
- 集合相关的
db.[documentName].help()
- 数据库相关的
mongoDB的API
所有文档
js版3.3.4-
数据库和集合命名规范
- 不能是空字符串
- 不得含有‘ ’(空格)、,、$、/、\、和\o(空字符)
- 应全部小写
- 最多64字节
- 数据库名称不能喝现有系统保留库同名,如admin,local以及config
- 这样的集合名字才是合法的
注意:db-text
名字也是合法的,但是不能通过db.[documentName]
来得到了,要改为db.getCollection(documentName)
,因为db-text会被当做减法操作
- mongoDB的shell内置javascript引擎可以直接执行js代码
function insert(object){
db.getCollection("db-text").insert(object)
}
insert({age:12})
- shell可以用eval
db.eval("return 'mongoDB'")
BSON
- BSON是JSON的扩展,它线增加了诸如日期,浮点灯JSON不支持的数据类型
BSON | |
---|---|
null | 用于表示空或者不存在的字段 |
布尔 | 数值true和false |
32位和64位整数 | Shell不支持 需用到其他高级语言的驱动来完成JS不可使用 |
64位浮点 | Shell中使用的数字其实全是这种类型{x:3.414} |
UTF-8 | 其实就是字符串类型 |
对象ID | 内置默认ID对象{_id:ObjectId()} |
日期 | {x:new Date()} |
正则 | {x:/uspcat/i} |
Javascript代码块 | {x:function(){...}} |
undefined | 为定义类型注意他和null不是一个类型 |
数组 | {gps:[20,56]} |
内嵌文档 | {x:{name:"uspcat"}} |
二进制 | 任意字节的字符串shell中时无法使用 |
查询
- 查询制定文档的数据
- 查询所有:
db.[documentName].find()
- 查询指定字段:
db.[documentName].find({age:7},{name:1})
,查询age=7的name字段 - 查询第一条数据:
db.[documentName].findOne()
- 查询所有:
- 查询集合中的文档 ,统计(count)、排序(sort)、分页(skip、limit)
db.customer.count();
db.customer.find().count();
db.customer.find({age:{$lt:5}}).count();
db.customer.find().sort({age:1}); //降序-1
db.customer.find().skip(2).limit(3);
db.customer.find().sort({age:-1}).skip(2).limit(3);
db.customer.find().sort({age:-1}).skip(2).limit(3).count();
db.customer.find().sort({age:-1}).skip(2).limit(3).count(0);
db.customer.find().sort({age:-1}).skip(2).limit(3).count(1);
$all
查询集合中的文档 ,$all主要用来查询数组中的包含关系,查询条件中只要有一个不包含就不返回
> db.c1.find()
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
> db.c1.find({age:{$all:[1,24]}})
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
>
$in
查询集合中的文档 ,$in,类似于关系型数据库中的IN
> db.c1.find()
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
> db.c1.find({age:{$in:[1,21,24]}})
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
>
$nin
查询集合中的文档 ,$nin,与$in相反
and条件查询
> db.c1.find({name:"xiaoxi",age:21})
{ "_id" : ObjectId("599d3cb5f22715cddac80dec"), "name" : "xiaoxi", "age" : 21 }
> db.c1.find({name:"xiaoxi",name:"xiaodong"}) //and条件都是name时,最后一个name生效
{ "_id" : ObjectId("599d3cc1f22715cddac80ded"), "name" : "xiaodong", "age" : 22 }
>
$or
查询集合中的文档 ,$or,相当于关系型数据库中的OR,表示或者的关系,例如查询name为xiaoxi或者name为xiaodong的文档,命令为:
> db.c1.find()
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
{ "_id" : ObjectId("599d3cb5f22715cddac80dec"), "name" : "xiaoxi", "age" : 21 }
{ "_id" : ObjectId("599d3cc1f22715cddac80ded"), "name" : "xiaodong", "age" : 22 }
{ "_id" : ObjectId("599d3ccbf22715cddac80dee"), "name" : "xiaonan", "age" : 23 }
{ "_id" : ObjectId("599d3cd4f22715cddac80def"), "name" : "xiaobei", "age" : 24 }
> db.c1.find({$or:[{name:"xiaoxi"},{name:"xiaodong"}]})
{ "_id" : ObjectId("599d3cb5f22715cddac80dec"), "name" : "xiaoxi", "age" : 21 }
{ "_id" : ObjectId("599d3cc1f22715cddac80ded"), "name" : "xiaodong", "age" : 22 }
>
$nor
查询集合中的文档 ,$nor,表示根据条件过滤掉某些数据,例如查询name不是user2,age不是3的文档,命令为:
db.customer.find({$nor:[{name:”user2”},{age:3}]})
> db.c1.find()
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
{ "_id" : ObjectId("599d3cb5f22715cddac80dec"), "name" : "xiaoxi", "age" : 21 }
{ "_id" : ObjectId("599d3cc1f22715cddac80ded"), "name" : "xiaodong", "age" : 22 }
{ "_id" : ObjectId("599d3ccbf22715cddac80dee"), "name" : "xiaonan", "age" : 23 }
{ "_id" : ObjectId("599d3cd4f22715cddac80def"), "name" : "xiaobei", "age" : 24 }
> db.c1.find({$nor:[{name:"zhangguorong"},{name:"xiaoxi"},{age:22}]})
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ccbf22715cddac80dee"), "name" : "xiaonan", "age" : 23 }
{ "_id" : ObjectId("599d3cd4f22715cddac80def"), "name" : "xiaobei", "age" : 24 }
$exits
查询集合中的文档 ,$exists,用于查询集合中存在某个键的文档或不存在某个键的文档,例如查询customer集合中存在name键的所有文档,可以使用 db.customer.find({name:{$exists:1}})
,
$exists:1表示真,指存在
$exists:0表示假,指不存在
> db.c2.find()
{ "_id" : ObjectId("599d40f1b63c48182175b59f"), "name" : "wangzhaoting", "desc" : "ydh" }
{ "_id" : ObjectId("599d4103b63c48182175b5a0"), "name" : "wangzhaoting", "age" : 24 }
> db.c2.find({age:{$exists:1}})
{ "_id" : ObjectId("599d4103b63c48182175b5a0"), "name" : "wangzhaoting", "age" : 24 }
> db.c2.find({name:{$exists:1}})
{ "_id" : ObjectId("599d40f1b63c48182175b59f"), "name" : "wangzhaoting", "desc" : "ydh" }
{ "_id" : ObjectId("599d4103b63c48182175b5a0"), "name" : "wangzhaoting", "age" : 24 }
>
游标
查询集合中的文档 ,类似于关系型数据库,mongodb中也有游标的概念
> db.c1.find()
{ "_id" : ObjectId("599d3aacf22715cddac80de9"), "name" : "zhangxueyou", "age" : [ 1, 21, 24, 88 ] }
{ "_id" : ObjectId("599d3ac3f22715cddac80dea"), "name" : "zhangguorong", "age" : [ 1, 38, 12, 77 ] }
{ "_id" : ObjectId("599d3b95f22715cddac80deb"), "name" : "zhangguorong", "age" : [ 1, 24, 12, 77 ] }
{ "_id" : ObjectId("599d3cb5f22715cddac80dec"), "name" : "xiaoxi", "age" : 21 }
{ "_id" : ObjectId("599d3cc1f22715cddac80ded"), "name" : "xiaodong", "age" : 22 }
{ "_id" : ObjectId("599d3ccbf22715cddac80dee"), "name" : "xiaonan", "age" : 23 }
{ "_id" : ObjectId("599d3cd4f22715cddac80def"), "name" : "xiaobei", "age" : 24 }
> var d = db.c1.find()
> d.hasNext()
true
> d.next()
{
"_id" : ObjectId("599d3aacf22715cddac80de9"),
"name" : "zhangxueyou",
"age" : [
1,
21,
24,
88
]
}
> d.next()
{
"_id" : ObjectId("599d3ac3f22715cddac80dea"),
"name" : "zhangguorong",
"age" : [
1,
38,
12,
77
]
}
>
插入
- 插入文档
db.[documentName].insert({})
- 批量插入文档
- shell 这样执行是错误的
db.[documentName].insert([{},{},{},……..])
,shell 不支持批量插入 - 想完成批量插入可以用mongo的应用驱动或是shell的for循环
- shell 这样执行是错误的
for(var i=0;i<10;i++){
db.persons.insert({name:"name"+i,age:20+i})
}
- Save操作
save操作和insert操作区别在于当遇到_id相同的情况下,save完成保存操作,insert则会报错
删除
删除文档中的数据
db.[documentName].remove({..})
例:db.persons.remove({name:"myNewName"})
删除库中的集合
db.[documentName].drop()
删除数据库
db.dropDatabase()
删除列表中所有数据
db.[documentName].remove()
集合的本身和索引不会被删除根据条件删除
db.[documentName].remove({})
删除集合text中name等于uspcat的纪录
db.text.remove({name:”uspcat”})
小技巧
如果你想清楚一个数据量十分庞大的集合
直接删除该集合并且重新建立索引的办法
比直接用remove的效率和高很多
更新
db.collection.update(criteria,objNew,upsert,multi)
- 参数说明:
- criteria:用于设置查询条件的对象
- objNew:用于设置更新内容的对象
- upsert:如果记录已经存在,更新它,否则新增一个记录,取值为0或1
- multi:如果有多个符合条件的记录,是否全部更新,取值为0或1
注意:默认情况下,只会更新第一个符合条件的记录
一般情况下后两个参数分别为0,1 ,即:db.collection.update(criteria,objNew,0,1)
- 强硬的文档替换式更新操作
db.[documentName].update({查询器},{修改器})
强硬的更新会用新的文档代替老的文档
- 主键冲突的时候会报错并且停止更新操作
因为是强硬替换当替换的文档和已有文档ID冲突的时候,则系统会报错
例:db.persons.update({_id:2},{_id:3,name:"haha"})
-
insertOrUpdate
操作
目的:查询器查出来数据就执行更新操作,查不出来就替换操作
做法:db.[documentName].update({查询器},{修改器},true)
- 批量更新操作
默认情况当查询器查询出多条数据的时候默认就修改第一条数据
如何实现批量修改
db.[documentName].update({查询器},{修改器},false, true)
- 第三个参数:false,表示不执行insert操作
- 第四个参数:true,表示进行批量操作
修改器
使用修改器来完成局部更新操作
- 数组定位器,如果数组有多个数值我们只想对其中一部分进行操作我们就要用到定位器($)
例子:
例如有文档
{name:”YFC”,age:27,books:[{type:’JS’,name:”EXTJS4”},{type:”JS”,name:”JQUERY”},{type:”DB”,name:”MONGODB”}]}
我们要把type等于JS的文档增加一个相同的作者author是USPCAT
办法:
db.text.update({"books.type":"JS"},{$set:{"books.$.author":"USPCAT"}})
- 切记修改器是放到最外面,后面要学的查询器是放到内层的
案例
- $set
db.persons.update({name:"name0"},{$set:{gender:"man"}})
- $inc
db.persons.update({age:20},{$inc:{age:10}})
- $unset
db.persons.update({age:30},{$unset:{gender:"man"}})
- $push
db.persons.insert({name:"myname",age:28,book:[]})
db.persons.update({name:"myname"},{$push:{book:"js"}})
db.persons.update({name:"myname"},{$push:{book:"extjs4"}})
- $pushAll
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
{ "_id" : 2, "name" : "name2" }
> db.persons.update({_id:2},{$pushAll:{book:["js","jquery"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
{ "_id" : 2, "name" : "name2", "book" : [ "js", "jquery" ] }
>
- $addToSet
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
> db.persons.update({_id:1},{$addToSet:{codes:"classs"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "classs" ] }
> db.persons.update({_id:1},{$addToSet:{codes:"var"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "classs", "var" ] }
> db.persons.update({_id:1},{$addToSet:{codes:"var"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "classs", "var" ] }
>
- $pop
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "classs", "var", "project" ] }
> db.persons.update({_id:1},{$pop:{codes:-1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "var", "project" ] }
> db.persons.update({_id:1},{$pop:{codes:1}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "var" ] }
>
- $pull
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "var", "js", "extjs" ] }
> db.persons.update({_id:1},{$pull:{codes:"var"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "js", "extjs" ] }
>
- $pullAll
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ "js", "extjs" ] }
> db.persons.update({_id:1},{$pullAll:{codes:["js","extjs"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ ] }
>
- $
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ ] }
> db.persons.insert({_id:2,name:"name2",books:[{type:"JS",name:"jsgj"},{type:"JS",name:"jquery"},{type:"DB",name:"mongoDB"}]})
WriteResult({ "nInserted" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ ] }
{ "_id" : 2, "name" : "name2", "books" : [ { "type" : "JS", "name" : "jsgj" }, { "type" : "JS", "name" : "jquery" }, { "type" : "DB", "name" : "mongoDB" } ] }
> db.persons.update({"books.type":"JS"},{$set:{"books.$.author":"uspcat"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1", "codes" : [ ] }
{ "_id" : 2, "name" : "name2", "books" : [ { "type" : "JS", "name" : "jsgj", "author" : "uspcat" }, { "type" : "JS", "name" : "jquery" }, { "type" : "DB", "name" : "mongoDB" } ] }
>
数组批量更新
- $addToSet与$each结合完成批量数组更新
db.text.update({_id:1000},{$addToSet:{books:{$each:[“JS”,”DB”]}}})
$each
会循环后面的数组把每一个数值进行$addToSet
操作 - 存在分配与查询效率
当document被创建的时候DB为其分配没存和预留内存当修改操作
不超过预留内层的时候则速度非常快反而超过了就要分配新的内存,则会消耗时间
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
{ "_id" : 2, "name" : "name2", "books" : [ ] }
> db.persons.update({_id:2},{$set:{books:["js"]}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
{ "_id" : 2, "name" : "name2", "books" : [ "js" ] }
> db.persons.update({_id:2},{$addToSet:{books:{$each:["js","DB","java"]}}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.persons.find()
{ "_id" : 0, "name" : "name0" }
{ "_id" : 1, "name" : "name1" }
{ "_id" : 2, "name" : "name2", "books" : [ "js", "DB", "java" ] }
>
- runCommand函数和findAndModify函数
runCommand可以执行mongoDB中的特殊函数
findAndModify就是特殊函数之一,他的作用是返回update或remove后的文档
runCommand({“findAndModify”:”processes”,
query:{查询器},
sort{排序},
new:true
update:{更新器},
remove:true
}).value
ps = db.runCommand({
"findAndModify":"persons",
"query":{"name":"text"},
"update":{"$set":{"email":"1221"}},
"new":true
}).value
do_something(ps)
http://www.cppblog.com/byc/archive/2011/07/15/151063.aspx