Mongodb简介
分布式存储,可扩展高性能的数据存储解决方案。介于关系和非关系数据库之间。面向文档的数据库
文档?/? 逗号分隔的键值对文档结构??
```
{
_id: ObjectId(7df78ad8902c)
title: 'MongoDB Overview',
description: 'MongoDB is no sql database',
by: 'yiibai.com',
url: 'http://www.yiibai.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100,
comments: [
{
user:'user1',
message: 'My first comment',
dateCreated: new Date(2011,1,20,2,15),
like: 0
},
{
user:'user2',
message: 'My second comments',
dateCreated: new Date(2011,1,25,7,45),
like: 5
}
]
}
//_id 12字节的十六进制数,保证每一份文件的唯一性,(可以提供_id同时插入文档,不提供自己产生。
//前4个字节为当前时间戳,未来3个字节的机器ID,接下来的2个字节的进程id MongoDB的服务器及剩余3个字节是简单的增量值。)
```
-
Nosql
nosql(not only sql)(RDMBDs)关系数据库管理系统
遵循ACID规则 -
与关系型数据库的对比
RDBMS | Mongodb |
---|---|
Database | Database |
Table | Collection |
Tuple/Row | Document |
column | Field |
Table Join | Embedded Documents |
Primary Key | Primary Key (Default key _id provided by mongodb itself) |
数据库服务器 | 客户端 |
---|---|
Mysqld/Oracle | mongod |
mysql/sqlplus | mongo |
Mongodb数据模型
-
mongodb设计模式的思考
1.根据用户要求设计架构? //怎么样的架构是优化的? 2.如果要将对象放在一起可以合并对象为一个文件,否则分开他们(确保不连接) 3.重复数据有限?磁盘空间便宜?(相比计算时间) 4.不需要连接写入,而是读 5.优化架构是最常见的用例 6.在模式上做复杂的聚集 //聚合操作?
-
网上例子
假设一个客户端需要一个数据库设计,设计一个博客网站,来看看 RDBMS 和 MongoDB 架构设计之间的差异。网站有以下要求。 - 每一个文章内容都有独特的标题,描述和网址。 - 每一个文章内容可以有一个或多个标签。 - 每一个文章内容都有其出版商总数和喜欢的名称。 - 每一个文章内容有评论以及名字,消息,时间和喜欢的用户。 - 对于每个文章,可以是零个或多个评论。 1.RDBMS模式设计 通过post_id w外键连接各张表 文章内容(post):id、 title、description、url、likes、post_by comment(评论):comment_id 、post_id、by_user、message、data_time、likes 标签(tag_list):id 、post_id、tag 2.MongoDB 模式 //只需要一个集合?? { _id: POST_ID title: TITLE_OF_POST, description: POST_DESCRIPTION, by: POST_BY, url: URL_OF_POST, tags: [TAG1, TAG2, TAG3], //RDBMs模式下的tag_list likes: TOTAL_LIKES, comments: [ { user:'COMMENT_BY', message: TEXT, dateCreated: DATE_TIME, like: LIKES }, { user:'COMMENT_BY', message: TEXT, dateCreated: DATE_TIME, like: LIKES } //RDBMs模式下的comment表 ] }
搭建Mongodb环境
RedHat/CentOs
1. vi /etc/yum.repos.d/mongodb-org-3.4.repo 文件,一遍 yum 命令直接安装
写入:
[mongodb-org-3.4]
name=MongoDB Repository
baseurl=http://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/
gpgcheck=1
enabled=1
gpgkey=http://www.mongodb.org/static/pgp/server-3.4.asc
//mongodb-org-server 提供默认的/etc/mongod.conf
2. sudo yum install -y mongodb-org (刚开始安装时,有点慢)
3. 配置SEliNUX??
4. 默认存放路径 /var/lib/mongo - 数据文件
/var/log/mongodb -- rizhi wenjian
/etc/mongod.conf 可以指定备用日志和数据文件目录
5. 启动Mongodb:
# sudo service mongod start
# mongod --dbpath=/data/mongodata/rs1 --logpath=/data/mongodata/rs1/rs1.log
//命令行启动 绝对路径
# mongod --config /var/lib/mongodb/conf/rs2.conf
//以配置文件的方式启动,可以查看配置文件是否有错
系统服务的方式启动
# vi /etc/init.d/mongod
6 注意事项:
1. 当bindip 本地没有问题时 ,局域网内无法连接,首先看IP是否能ping通,防火墙是否关闭
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 27017 -j ACCEPT
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
firewall-cmd --state #查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
Mongodb语法
-
创建数据库
use database_name //如果不存在创建,存在则返回现有数据库 //示例代码 >use mydb switched to db mydb >show dbs //有哪些数据库 local 0.78125GB test 0.23012GB >db //显示当前数据库 mydb >db.movie.insert({"name":"yiibai tutorials"}) //当数据库中无数据时,不显示,插入数据后使用show命令就可以显示了 >show dbs local 0.78125GB mydb 0.23012GB test 0.23012GB **dropDatabase** //删除数据库 >use mydb switched to db mydb >db.dropDatabase() >{ "dropped" : "mydb", "ok" : 1 } >
-
创建集合
**createCollection()** 1.db.createCollection(name, options) //Options 类型 Document (可选)指定有关内存大小和索引选项 //当插入文档,MongoDB 第一检查大小字段封顶集合,然后它会检查最大的字段中。 >use test switched to db test >db.createCollection("mycollection") { "ok" : 1 } > 2.在MongoDB中,不需要创建集合。当插入一些文件 MongoDB 自动创建的集合 >db.yiibai.insert({"name" : "yiibai"}) >show collections mycol mycollection system.indexes yiibai > 3.drop() db.COLLECTION_NAME.drop() >use mydb switched to db mydb >show collections mycol mycollection system.indexes yiibai > >db.mycollection.drop() //删除mycollection集合 true > >show collections mycol system.indexes yiibai > insert() >db.COLLECTION_NAME.insert(document) >db.mycol.insert({ _id: ObjectId(7df78ad8902c), title: 'MongoDB Overview', description: 'MongoDB is no sql database', by: 'tutorials yiibai', url: 'http://www.yiibai.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }) //_id: ObjectId(4 bytes timestamp, 3 bytes machine id, 2 bytes process id, 3 bytes incrementer) _id自动生成id的命名规则 //插入单个查询的多个文档 >db.post.insert([ { title: 'MongoDB Overview', description: 'MongoDB is no sql database', by: 'tutorials yiibai', url: 'http://www.yiibai.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }, { title: 'NoSQL Database', description: 'NoSQL database doesn't have tables', by: 'tutorials yiibai', url: 'http://www.yiibai.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 20, comments: [ { user:'user1', message: 'My first comment', dateCreated: new Date(2013,11,10,2,35), like: 0 } ] } ]) //为什么第一个记录可以没有comment字段呢??? 要插入文件 db.mycollectionname.save(document) 与insert()类似
-
mongodb查找
find() | findOne()---此方法只返回一个文件 db.COLLECTION_NAME.find() //nd() 方法将在非结构化的方式显示所有的文件。 >db.mycol.find().pretty() //格式化的显示结果 RDBMS Where子句和MongoDB等同语句: < > <e >e &ne {<key>:<value>} {<key>:{$lt:<value>}} >db.mycol.find({key1:value1, key2:value2}).pretty() //类似于and条件 //执行or语句 &or >db.mycol.find( { $or: [ {key1: value1}, {key2:value2} ] } ).pretty() //执行and 和 or >db.mycol.find("likes": {$gt:10}, $or: [{"by": "yiibai"}, {"title": "MongoDB Overview"}] }).pretty() 键的筛选: db.user.find({},{"_id":0})//指定find的第二个参数1则返回,0过滤 关联查询: db.user.find("age":{"$in":[20,25,26]}) db.user.find("age":{"$nin":[20,25,26]}) 特定类型的查询 1. null db.user.find("sex":{"$in":[null]})//null不仅能匹配自身,还能匹配键不存在的文档 2. 正则表达式 db.user.find({"name":/^user/}) 3. 数组查询 db.food.find({fruit:{$all:["apple","banana"]}}) //$all 多个元素匹配 //$size 查询指定长度的数组 //$slice 返回数组的一个子集合 db.blog.find({},{"comments":{"$slice":1}}) //[]偏移量 内嵌文档查询: db.person.find({name:{first:"jock","last":"shob"}}) db.person.find({"name.first":"jock"}) $where 与JavaScript的结合 游标: mongodb使用游标(cursor)来返回find的执行结果,客户端使用游标对最终结果进行有效的控制,比如分页,排序 limit,skip和sort(1为升序,-1为降序) 高级查询: 包装查询
update()
db.COLLECTION_NAME.update(SELECTIOIN_CRITERIA, UPDATED_DATA)
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Tutorials Yiibai Overview"}db.mycol.update({'title':'MongoDB Overview'},{$set:{'title':'New MongoDB Tutorial'}})
db.mycol.find()
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"New MongoDB Tutorial"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"}//MongoDB默认将只更新单一的文件,来更新多个你需要设置参数置'multi' 为true
db.mycol.update({'title':'MongoDB Overview'},{$set:{'title':'New MongoDB Tutorial'}},{multi:true})
save() //替换现有的文档和通过新的文档 save() 方法
db.mycol.save(
{
"_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai New Topic", "by":"Yiibai"
}
)
db.mycol.find()
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"Yiibai New Topic", "by":"Yiibai"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"}remove() //从集合中删除文档,不加餐素默认整个删除,justOne可选参数,只删除一个文件
db.COLLECTION_NAME.remove(DELLETION_CRITTERIA)
//deletion criteria 删除标准{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"}
>db.mycol.remove({'title':'MongoDB Overview'})
>db.mycol.find()
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"}
>
Limit() //限制输出记录的个数
>db.COLLECTION_NAME.find().limit(NUMBER)
{ "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"}
{ "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"}
{ "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"}
>db.mycol.find({},{"title":1,_id:0}).limit(2)
{"title":"MongoDB Overview"}
{"title":"NoSQL Overview"}
>
skip()方法 //跳过文档
>db.mycol.find({},{"title":1,_id:0}).limit(1).skip(1)
{"title":"NoSQL Overview"}
> //跳过第一个文档,只显示第二个文档
sort() //排序
>db.COLLECTION_NAME.find().sort({KEY:1}) // 1用于升序排列,而-1用于降序。key为要搜索文档的键值
```
- 数据类型
String : 这是最常用的数据类型来存储数据。在MongoDB中的字符串必须是有效的UTF-8。
Integer : 这种类型是用来存储一个数值。整数可以是32位或64位,这取决于您的服务器。
Boolean : 此类型用于存储一个布尔值 (true/ false) 。
Double : 这种类型是用来存储浮点值。
Min/ Max keys : 这种类型被用来对BSON元素的最低和最高值比较。
Arrays : 使用此类型的数组或列表或多个值存储到一个键。
Timestamp : 时间戳。这可以方便记录时的文件已被修改或添加。
Object : 此数据类型用于嵌入式的文件。
Null : 这种类型是用来存储一个Null值。
Symbol : 此数据类型用于字符串相同,但它通常是保留给特定符号类型的语言使用。
Date : 此数据类型用于存储当前日期或时间的UNIX时间格式。可以指定自己的日期和时间,日期和年,月,日到创建对象。
Object ID : 此数据类型用于存储文档的ID。
Binary data : 此数据类型用于存储二进制数据。
Code : 此数据类型用于存储到文档中的JavaScript代码。
Regular expression : 此数据类型用于存储正则表达式
操作符 $type
db.col.find({"key":{$type:2}}) //查找key(键)类型为2的数据,2代表string
-
Mongodb 投影
投影:只选择必要数据而不是选择一个文件的整个数据 比如find()方法
find() //显示文档的所有字段,需要设置字段列表值1或0。 //1用来显示字段而0是用来隐藏字段。 { "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overview"} { "_id" : ObjectId(5983548781331adf45ec6), "title":"NoSQL Overview"} { "_id" : ObjectId(5983548781331adf45ec7), "title":"Yiibai Overview"} >db.mycol.find({},{"title":1,_id:0}) {"title":"MongoDB Overview"} //_id 字段不显示 {"title":"NoSQL Overview"} {"title":"Yiibai Overview"} >
-
Mongodb 索引
如果没有索引,Mongodbdb必须扫描每一个文档的集合,会有大量的数据需要处理
数据结构: 树索引是一种特殊的数据结构,存储在一个容易遍历读取的数据集合中。索引是对数据库表中一列或多列的值进行排序的一种结构
ensureIndex() >db.COLLECTION_NAME.ensureIndex({KEY:1}) //1是按升序排列的字段名称。要创建降序索引,需要使用-1 >db.mycol.ensureIndex({"title":1}) //给title创建索引,1是升序,-1是降序 > >db.mycol.ensureIndex({"title":1,"description":-1}) //为title创建索引(索引数据结构,给title建立索引排序 便于查找) 2.接收可选参数 //可选参数 >db.mycol.ensureIndex({open:1,close:1},{background:true}) >db.mycol.getINdexes() //获得当前索引
- 索引深入学习
//未加索引的状况,每个文档都要遍历一遍
db.user.find({username:"user101"}).explain() //explain 查看mongodb在执行查询过程中都干了什么
{
"cursor":"",
"nscanned":100000000000000,
"n":1,
"millis":721,
.....
}
上述中“nscanned”代表查询文档总数,“n”代表查询结果数 “millis”代表查询时间毫秒数
//添加索引,查询时间明显快速,最多只有64个索引(峰值),特定的集合上不应该有两个以上的索引,占内存 ,1代表方向
db.user.ensureIndex({"username":1})
db.user.find({username:"user101"}).explain() //explain 查看mongodb在执行查询过程中都干了什么
{
"cursor":"",
"nscanned":1,
"n":1,
"millis":3,
.....
}
复合索引
//索引的值时按一定顺序排列的,因此,使用索引键进行排序非常快
>db.users.ensureIndex({"age":1,"username":1}) //这就是一个复合索引,多字段
目的:优化查询,提高查询效率 理解引擎是如何工作的
坑: 如果结果集的大小超过32MB,就会出错,拒绝对如此多的数据进行排序,操作符查询
基于多个查询条件进行排序是,索引方向才是比较重要的
索引对象和数组
//可以对任意深层次的字段建立索引
>db.user.ensureIndex({"loc.city":1}) //city字段
//db.user.find({"loc":{"ip":123,"city":shenzhen}}) 对city字段才有效 ,对loc.city无效
-
Mongodb 聚合
aggregate() //处理数据(如统计平均值,求和),并返回数据结果。在SQL COUNT(*)和group by 相当于MongoDB的聚集 //$sum $avg $min $max $push $addToSet $first $last by_user: 'yiibai yiibai', url: 'http://www.yiibai.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 }, { _id: ObjectId(7df78ad8902d) title: 'NoSQL Overview', description: 'No sql database is very fast', by_user: 'yiibai yiibai', url: 'http://www.yiibai.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 10 }, { _id: ObjectId(7df78ad8902e) title: 'Neo4j Overview', description: 'Neo4j is no sql database', by_user: 'Neo4j', url: 'http://www.neo4j.com', tags: ['neo4j', 'database', 'NoSQL'], likes: 750 }, >db.mycol.aggregate([{$group:{_id:"$by_user",num_tutorial:{$sum:1}}}]) { "result" : [ { "_id" : "yiibai yiibai", "num_tutorial" : 2 }, { "_id" : "yiibai yiibai", "num_tutorial" : 1 } ], "ok" : 1 } > 管道的概念:当前命令的输出结果作为下一个命令的参数 Mongodb的聚合管道将Mongodb文档在一个管道处理完毕后将结果传递给下一个管道处理,管道操作时刻重复的 $project:修改输入文档的结构,重新安排文档包含的字段(重命名,增加,删除) //db.article.aggregate( { $project : { _id : 0 , //不包含_id字段 title : 1 , //包含该字段 author : 1 }}); $match:过滤 $limit $skip $unwind //目标字段不存在,该文档被忽略过滤 $group :将集合中的文档进行分组,可用于统计结果 //$group的时候必须要指定一个_id域,同时也可以包含一些算术类型的表达式操作符,无序的,不对大量个数的文档进行分组 $sort $geoNear
-
Mongodb 复制
-
Mongodb 分片
-
Mongodb 关系
表示多个文档之间的在逻辑上的联系 文档间通过嵌入和引用来建立关系 关系: 1:1(1对1) 1:N N:1 N:N
//user文件示例文档 { "_id":ObjectId("52ffc33cd85242f436000001"), "name": "Tom Hanks", "contact": "987654321", "dob": "01-01-1991" } //address文件的示例文档结构: { "_id":ObjectId("52ffc4a5d85242602e000000"), "building": "22 A, Indiana Apt", "pincode": 123456, "city": "Los Angeles", "state": "California" }
嵌入建模
{ "_id":ObjectId("52ffc33cd85242f436000001"), "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin", "address": [ { "building": "22 A, Indiana Apt", "pincode": 123456, "city": "Los Angeles", "state": "California" }, { "building": "170 A, Acropolis Apt", "pincode": 456789, "city": "Chicago", "state": "Illinois" }] } //这种方法保持在一个单一的文件,它可以很容易地检索和维护所有相关数据。 整份文件,可检索这样一个查询 >db.users.findOne({"name":"Tom Benzamin"},{"address":1}) 缺点:嵌入的文档过长并且不断增加,影响读写性能
模型引用关系
如上把用户数据文档和用户地址数据文档分开维护,通过引用文档id字段来建立关系{ "_id":ObjectId("52ffc33cd85242f436000001"), "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin", "address_ids": [ ObjectId("52ffc4a5d85242602e000000"), //引用的id对应的数据 ObjectId("52ffc4a5d85242602e000001") ] } //需要两个查询 >var result = db.users.findOne({"name":"Tom Benzamin"},{"address_ids":1}) >var addresses = db.address.find({"_id":{"$in":result["address_ids"]}})
Mongodb引用有两种:
1.手动引用 2.DBRefs(数据库引用) DBRef的形式: { $ref: 集合名称 ,$id: 引用的id $db: 数据库名称,可选参数 } { "_id":ObjectId("53402597d852426020000002"), "address": { "$ref": "address_home", "$id": ObjectId("534009e4d852427820000002"), "$db": "yiibai"}, "contact": "987654321", "dob": "01-01-1991", "name": "Tom Benzamin" } >var user = db.users.findOne({"name":"Tom Benzamin"}) >var dbRef = user.address >db[dbRef.$ref].findOne({"_id":(dbRef.$id)})
-
导入和导出
mongoexport --help
mongoexport -h 101.37.83.106:27017 -u txbyw -p txbyw -d tivs_audio -c Album --type=json -o /home/l123/Documents/mongodata_export_Album --authenticationDatabase admin
mongoimport -h localhost -d tivs_audio -c Album /home/l123/Documents/mongodata_export_Album --authenticationDatabase admin
网友评论