nodejs-第四天-MongoDB
MongoDB安装
1. Mac系统上安装
使用Homebrew安装
$ brew updata // 更新Homebrew的package数据库
$ brew install mongodb
2. 启动MongoDB
$mongod --config /usr/local/etc/mongod.conf
// sudo mongod
3. 使用MongoDB shell
$ mongo
MongoDB是什么?
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
特点是:
高性能、易部署、易使用、存储数据方便
MongoDB概念
SQL | MongoDB | 解释 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
1. 数据库
- 一个mongodb中可以建立多个数据库
- MongoDB的默认数据库为“db”,该数据库存储在data目录中。
- MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中
show dbs 列出所有数据库
db //显式当前使用的数据库
use xxx 切换数据库
数据库的命名:通过标识符,使用utf8字符串
- 非空
- 不允许出现特殊字符$,/
- 全部小写,最多64个字节
- 有一些特殊保留数据库,如local、admin、config,命名时避免使用
2. 文档
文档是一个键值(key-value)对(即BSON)。MongoDB的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是MongoDB非常突出的特点。
3. 集合
集合就是 MongoDB文档组,类似于RDBMS(关系型数据库管理系统)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着对集合可以插入不同格式和类型的数据,但通常情况下我们插入的数据都会有一定的关联性。
结合的命名
- 不能是空字符串
- 不允许出现- 0
- 不能以system.开头,这是系统保留的前缀
- 不能包含保留字,$
4.MongoDB数据类型
类型 | 描述 |
---|---|
null | 用于表示空值或者不存在的字段{“x”,null} |
布尔 | ‘true’和’false’{“x”,true} |
32位整数 | Shell中这个类型不可用,MongoDB在控制台使用JS引擎进行输入,而JS仅支持64位浮点数,所以32位整数将会被自动转义 |
64位整数 | Shell中这个类型不可用, 64位整数与32位整数一样,在MongoDB控制台使用时,会转义成64位浮点数 |
64位浮点数 | Shell中的数字都是这种类型,下面是浮点数{“x”:3.14}、{“x”:3} |
字符串 | UTF-8字符串都可表示为字符串类型的数据{“x”:”foobar”} |
符号 | Shell不支持这种类型,将自动转义成字符串 |
对象ID | 对象id是文档的12字节的唯一ID,时间戳 |
日期 | 日期类型存储的是从标准纪元开始的毫秒数{“x”:new Date()} |
正则表达式 | 文档中可以包含正则表达式,其正则表达式采用JS语法来表示{“x”:/foobar/i} |
代码 | 文档中可以包含js代码{“x”:function(){…}} |
二进制数据 | 二进制数据可以由任意字节的串组成,不过Shell无法使用 |
最大值 | BSON包括一个特殊类型,表示可能的最大值Shell无法使用 |
最小值 | BSON包括一个特殊类型,表示可能的最小值Shell无法使用 |
未定义 | 文档中也可以使用未定义类型{“x”:undefined} |
数组 | 值的集合或者列表可以表示成数组{“x”:[“a”,”b”,”c”]} |
内嵌文档 | 文档可以包含别的文档{“x”:{“foo”:”bar”}} |
MongoDB操作
1. 数据库常用命名
- Help查看提示命令
help
- db.help()
- db.test.help()
- db.test.find().help()
- 创建/切换数据库
- use music
- 查询数据库
- show dbs
- 查看当前使用的数据库
- db/db.getName()
- 显示当前DB状态
- db.stats()
- 查看当前DB版本
- db.version()
- 查看当前DB的链接机器地址
- db.getMongo()
- 删除数据库
- db.dropDatabase()
2. shell操作数据库
> use music
switched to db music
> show dbs // 当前列表里没有music数据库,因为没有数据
> db.albums.insertOne({'title':'生命之花'})
{
"acknowledged" : true,
"insertedId" : ObjectId("591b158a71d7222a7a0d7f60")
}
> db.albums.find()
{ "_id" : ObjectId("591b158a71d7222a7a0d7f60"), "title" : "生命之花" }
> show dbs //插入数据后,有music数据库
music 0.000GB
> db
music
> db.getName()
music
> db.stats()
{
"db" : "music",
"collections" : 1,
"views" : 0,
"objects" : 1,
"avgObjSize" : 46,
"dataSize" : 46,
"storageSize" : 16384,
"numExtents" : 0,
"indexes" : 1,
"indexSize" : 16384,
"ok" : 1
}
> db.version()
3.4.3
> db.getMongo()
connection to 127.0.0.1:27017
> db.dropDatabase() //删除数据库
{ "dropped" : "music", "ok" : 1 }
Collection 聚集集合操作
1. 创建一个聚集集合
db.createCollection(“collName”, {size: 20, capped: true, max: 100});
db.collName.isCapped(); //判断集合是否为定容量
> db.createCollection('albums',{size:20,capped:true,max:100})
{ "ok" : 1 }
capped:true 将集合固定大小,可以提高访问数据库的效率,插入数据时,会自动进行顺序管理
> db.albums.isCapped() //判断集合是否为定容量
true
size的优先级大于max
2. 得到指定名称的聚集集合
> db.getCollection('albums')
music.albums
3. 得到当前db的所有聚集集合
> db.getCollectionNames()
[ "albums" ]
4. 显示当前db所有聚集的状态
db.printCollectionStats()
添加、修改与删除集合数据
1. 添加
> db.albums.insertOne({title:'生命之花'})
> db.albums.insertMany([{title:'再见理想'},{title:'飞船'}])
> db.albums.insert([{title:'光辉岁月'},{title:'hello'}])
> db.albums.save({title:'21'})
2. 修改
修改所有数据
db.albums.updateMany(
{},
{
$set:{artist:'adele'}
}
)
> db.albums.find()
{ "_id" : ObjectId("591b1d7871d7222a7a0d7f61"), "title" : "生命之花", "artist" : "adele" }
{ "_id" : ObjectId("591b1e0071d7222a7a0d7f62"), "title" : "再见理想", "artist" : "adele" }
{ "_id" : ObjectId("591b1e0071d7222a7a0d7f63"), "title" : "飞船", "artist" : "adele" }
{ "_id" : ObjectId("591b1eac71d7222a7a0d7f64"), "title" : "光辉岁月", "artist" : "adele" }
{ "_id" : ObjectId("591b1eac71d7222a7a0d7f65"), "title" : "hello", "artist" : "adele" }
{ "_id" : ObjectId("591b1ee971d7222a7a0d7f66"), "title" : "21", "artist" : "adele" }
修改一条数据
>db db.albums.updateMany(
{title:'光辉岁月'},
{
$set:{artist:'Beyond'}
}
)
{ "_id" : ObjectId("591b1eac71d7222a7a0d7f64"), "title" : "光辉岁月", "artist" : "Beyond" }
3. 删除
删除一条记录
> db.albums.deleteOne({artist:'adele'})
{ "acknowledged" : true, "deletedCount" : 1 }
> db.albums.remove({artist:'adele'},true)
WriteResult({ "nRemoved" : 1 })
删除多条记录
> db.albums.deleteMany({artist:'adele'})
{ "acknowledged" : true, "deletedCount" : 3 }
> db.albums.remove({})
WriteResult({ "nRemoved" : 1 })
4. 查询修改删除
db.users.findAndModify({
query: {age: {$gte: 25}},
sort: {age: -1},
update: {$set: {name: 'a2'}, $inc: {age: 2}},
remove: true
});
db.runCommand({ findandmodify : "users",
query: {age: {$gte: 25}},
sort: {age: -1},
update: {$set: {name: 'a2'}, $inc: {age: 2}},
remove: true
});
参数 | 详解 | 详解 |
---|---|---|
query | 查询过滤条件 | {} |
sort | 如果多个文档符合查询过滤条件,将以该参数指定的排列方式选择出排在首位的对象,该对象将被操作 | {} |
remove | 若为true,被选中对象将在返回前被删除 | N/A |
update | 一个 修改器对象 | N/A |
new | 若为true,将返回修改后的对象而不是原始对象。在删除操作中,该参数被忽略。 | FALSE |
upsert | 创建新对象若查询结果为空 | FALSE |
聚集集合查询
1. 查询所有记录
db.userInfo.find();
相当于:select* from userInfo;
2.查询去重后数据
db.userInfo.distinct(“name”);
相当于:select distict name from userInfo;
3. 查询age = 22的记录
db.userInfo.find({“age”: 22});
相当于: select * from userInfo where age = 22;
4. 查询age > 22的记录
db.userInfo.find({age: {$gt: 22}});
相当于:select * from userInfo where age >22;
5. 查询age < 22的记录
db.userInfo.find({age: {$lt: 22}});
相当于:select * from userInfo where age <22;
6. 查询age >= 25的记录
db.userInfo.find({age: {$gte: 25}});
相当于:select * from userInfo where age >= 25;
7. 查询age <= 25的记录
db.userInfo.find({age: {$lte: 25}});
8. 查询age >= 23 并且 age <= 26
db.userInfo.find({age: {
gte:23,
lte: 26}});
查询name中包含 mongo的数据
9. db.userInfo.find({name: /mongo/});
//相当于%%
select * from userInfo where name like ‘%mongo%’;
10. 查询name中以mongo开头的
db.userInfo.find({name: /^mongo/});
select * from userInfo where name like ‘mongo%’;
11. 查询指定列name、age数据
db.userInfo.find({}, {name: 1, age: 1}); // 只访问name和age两列的内容,1位标识
相当于:select name, age from userInfo;
12. 查询指定列name、age数据, age > 25
db.userInfo.find({age: {$gt: 25}}, {name: 1, age: 1});
相当于:select name, age from userInfo where age >25;
13. 按照年龄排序
升序:db.userInfo.find().sort({age: 1}); // 1 为标识,升序
降序:db.userInfo.find().sort({age: -1}); // -1 为标识,降序
14.查询name = zhangsan, age = 22的数据
db.userInfo.find({name: ‘zhangsan’, age: 22});
相当于:select * from userInfo where name = ‘zhangsan’ and age = ’22’;
15.查询前5条数据
db.userInfo.find().limit(5);
相当于:select top 5 * from userInfo;
16. 查询10条以后的数据
db.userInfo.find().skip(10);
相当于:select * from userInfo where id not in (
select top 10 * from userInfo
);
17. 查询在5-10之间的数据
db.userInfo.find().limit(10).skip(5);
18. or与 查询
db.userInfo.find({$or: [{age: 22}, {age: 25}]});
相当于:select * from userInfo where age = 22 or age = 25;
19. 查询第一条数据
db.userInfo.findOne();
相当于:selecttop 1 * from userInfo;
db.userInfo.find().limit(1);
20. 查询某个结果集的记录条数
db.userInfo.find({age: {$gte: 25}}).count();
相当于:select count(*) from userInfo where age >= 20;
21. 按照某列进行排序
db.userInfo.find({sex: {$exists: true}}).count();
相当于:select count(sex) from userInfo;
聚集集合查询shell 操作
https://api.douban.com/v2/movie/top250获取豆瓣电影数据
将”subjects”:的数据插入到db.movie.insertMany()
中,再写入到数据库
#
db.movie.find({year:'1994'},{title:1, year:1})
{ "_id" : ObjectId("591b296971d7222a7a0d7f67"), "title" : "肖申克的救赎", "year" : "1994" }
{ "_id" : ObjectId("591b296971d7222a7a0d7f68"), "title" : "这个杀手不太冷", "year" : "1994" }
{ "_id" : ObjectId("591b296971d7222a7a0d7f6a"), "title" : "阿甘正传", "year" : "1994" }
若不显示_id字段内容
> db.movie.find({year:'1994'},{title:1, year:1, _id:0})
{ "title" : "肖申克的救赎", "year" : "1994" }
{ "title" : "这个杀手不太冷", "year" : "1994" }
{ "title" : "阿甘正传", "year" : "1994" }
显式title,year和rating.averag
db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0})
{ "rating" : { "average" : 9.6 }, "title" : "肖申克的救赎", "year" : "1994" }
{ "rating" : { "average" : 9.4 }, "title" : "这个杀手不太冷", "year" : "1994" }
{ "rating" : { "average" : 9.5 }, "title" : "霸王别姬", "year" : "1993" }
{ "rating" : { "average" : 9.4 }, "title" : "阿甘正传", "year" : "1994" }
{ "rating" : { "average" : 9.5 }, "title" : "美丽人生", "year" : "1997" }
{ "rating" : { "average" : 9.2 }, "title" : "千与千寻", "year" : "2001" }
{ "rating" : { "average" : 9.4 }, "title" : "辛德勒的名单", "year" : "1993" }
{ "rating" : { "average" : 9.2 }, "title" : "泰坦尼克号", "year" : "1997" }
{ "rating" : { "average" : 9.2 }, "title" : "盗梦空间", "year" : "2010" }
{ "rating" : { "average" : 9.3 }, "title" : "机器人总动员", "year" : "2008" }
{ "rating" : { "average" : 9.2 }, "title" : "海上钢琴师", "year" : "1998" }
{ "rating" : { "average" : 9.1 }, "title" : "三傻大闹宝莱坞", "year" : "2009" }
{ "rating" : { "average" : 9.2 }, "title" : "忠犬八公的故事", "year" : "2009" }
{ "rating" : { "average" : 9.2 }, "title" : "放牛班的春天", "year" : "2004" }
{ "rating" : { "average" : 9.2 }, "title" : "大话西游之大圣娶亲", "year" : "1995" }
{ "rating" : { "average" : 9.2 }, "title" : "教父", "year" : "1972" }
{ "rating" : { "average" : 9.1 }, "title" : "龙猫", "year" : "1988" }
{ "rating" : { "average" : 9 }, "title" : "楚门的世界", "year" : "1998" }
{ "rating" : { "average" : 9.2 }, "title" : "乱世佳人", "year" : "1939" }
{ "rating" : { "average" : 9.1 }, "title" : "天堂电影院", "year" : "1988" }
符合条件的条数
db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0}).size()
20
limit 显式指定数目
> db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0}).limit(5)
{ "rating" : { "average" : 9.6 }, "title" : "肖申克的救赎", "year" : "1994" }
{ "rating" : { "average" : 9.4 }, "title" : "这个杀手不太冷", "year" : "1994" }
{ "rating" : { "average" : 9.5 }, "title" : "霸王别姬", "year" : "1993" }
{ "rating" : { "average" : 9.4 }, "title" : "阿甘正传", "year" : "1994" }
{ "rating" : { "average" : 9.5 }, "title" : "美丽人生", "year" : "1997" }
skip 跳过制定数的数据
> db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0}).skip(15)
{ "rating" : { "average" : 9.2 }, "title" : "教父", "year" : "1972" }
{ "rating" : { "average" : 9.1 }, "title" : "龙猫", "year" : "1988" }
{ "rating" : { "average" : 9 }, "title" : "楚门的世界", "year" : "1998" }
{ "rating" : { "average" : 9.2 }, "title" : "乱世佳人", "year" : "1939" }
{ "rating" : { "average" : 9.1 }, "title" : "天堂电影院", "year" : "1988" }
limit和skip 3-5条数据
> db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0}).skip(2).limit(3)
{ "rating" : { "average" : 9.5 }, "title" : "霸王别姬", "year" : "1993" }
{ "rating" : { "average" : 9.4 }, "title" : "阿甘正传", "year" : "1994" }
{ "rating" : { "average" : 9.5 }, "title" : "美丽人生", "year" : "1997" }
sort 排序 1 为升序,-1为降序
> db.movie.find({},{title:1, year:1, 'rating.average':1, _id:0}).sort({'rating.average':1})
条件查询
> db.movie.find({'rating.average':{$gt:9.4}},{title:1, 'rating.average':1, _id:0})
{ "rating" : { "average" : 9.6 }, "title" : "肖申克的救赎" }
{ "rating" : { "average" : 9.5 }, "title" : "霸王别姬" }
{ "rating" : { "average" : 9.5 }, "title" : "美丽人生" }
按指定内容查询
> db.movie.find({genres:{$in:['犯罪']}},{title:1, genres:1, _id:0})
{ "genres" : [ "犯罪", "剧情" ], "title" : "肖申克的救赎" }
{ "genres" : [ "剧情", "动作", "犯罪" ], "title" : "这个杀手不太冷" }
{ "genres" : [ "剧情", "犯罪" ], "title" : "教父" }
node中使用MongoDB
var mongodb = require('mongodb')
// 创建数据库的连接
var server = new mongodb.Server(
'localhost',
27017,
{auto_reconnect:true}
)
// 创建数据的连接
var db = new mongodb.Db(
'movies',
server,
{safe: true}
)
// 测试数据库连接
db.open(function(err, db){
if (err){
console.log('log-'+ err)
} else {
console.log('log-connect mongodb success')
db.collection('movie', {safe: true}, function(err, conn){
if (err){
console.log(err)
} else {
conn.find({}, {title:1, year:1, _id:0}).limit(3).skip(3).toArray(function(err, res){
if(!err){
res.forEach(function(value){
console.log(value.title)
})
}
})
}
})
}
})
//打印结果
//阿甘正传
//美丽人生
//千与千寻