聚合、联表见详情
MongoDB脚本编写学习
准备
环境:win10
工具:Robo 3T 1.1.1(自带shell)、cmd
一、创建/切换/查看/删除数据库
1.1、创建/切换数据库(带例子,下同)
> use test1
switched to db test1
如果数据库不存在,则创建数据库,否则切换到指定数据库。
1.2、查看数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
注:新建的没有数据的数据库这里是显示不出来的,比如我新建的test1,需要在新建命令后插入一行数据.
> use test1
> db.lll.insert({name:'测试'})
1.3、删除数据库
要删除数据库,先进入该数据库
> use test1
switched to db test1
然后使用删除命令:db.dropDatabase()
> db.dropDatabase() // 删除当前数据库
{ "dropped" : "test1", "ok" : 1 }
二、集合操作
2.1、创建集合/插入文档
- 方式1
> db.COLLECTION_NAME.insert(document)
没有该集合则自动创建,有则直接插入文档
- 方式2
> db.createCollection(name, options)
第一个参数是集合名称,第二个是集合的相关配置(配置可以省略默认)
字段 | 类型 | 描述 |
---|---|---|
capped | Boolean | (可选)如果为真,则启用有上限的集合。封顶集合是一个固定大小的集合,当它达到最大大小时自动覆盖其最老的条目。 如果指定为真,还需要指定size参数。 |
size | number | (可选)为有上限的集合指定最大字节大小。如果capped为真,那么还需要指定该字段。 |
max | number | (可选)指定上限集合中允许的最大文档数量。 |
2.2、查询已有集合
> show collections
2.3、删除集合
命令:db.COLLECTION_NAME.drop()
示例:
删除test数据库中的test1集合
> db.test1.drop()
true
三、文档操作
3.1、文档插入
文档插入有insert()
和save()
两个方法
- insert:
db.COLLECTION_NAME.insert(document)
示例:
> db.test1.insert({
title: 'MongoDB 入门',
description: 'MongoDB是开源的NoSQL数据库',
by: 'test1.com',
url: 'https://www.test1.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 888
})
可以一次插入多个文档,文档中还可以带有文档数组,如下
> db.test1.insert([
{
title: 'MongoDB 入门',
description: 'MongoDB是一个以文档为中心的NOSQL数据库',
by: 'test1.com',
url: 'https://www.test1.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 88
},
{
title: 'MongoDB 优势',
description: "MongoDB相对于RDBMS的优势",
by: 'test1.com',
url: 'https://www.test1.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 89,
comments: [
{
user:'user1',
message: 'My first comment',
dateCreated: new Date(2020,11,19,2,35),
like: 0
}
]
}
])
在insert()中指明_id,如果集合中已经存在该 id,则插入失败,如果数据库中既不存在id,且insert()也没有指明,则有数据库自动生成一个唯一id
- save():
db.COLLECTION_NAME.save(document)
没有指定_id的情况下,save的情况和insert是一样的,如果指定了id,且数据库中存在id文档,则覆盖该文档所有数据
四、文档查询操作
4.1、find()方法
为了更好显示查询效果,我们新建books集合,并批量插入(for)一些数据:
> db.createCollection('books') // 创建books集合
> for(var i = 0; i < 50; i++){ // 批量插入五十条
db.books.insert(
{
name:'《朝花夕拾》',
price:50 + i,
info:'测试数据' + i,
publish:'人民出版社',
createTime:new Date(),
updateTime:new Date()
}
)
}
查询示例:
> db.getCollection('books').find({})
单独使用find()是没有结构化的,想要格式化显示结果,可以在后边加上pretty()
> db.getCollection('books').find({}).pretty()
find()方法里面可以传入查询条件,下表是对应语法的解释以及和sql的对比
操作 | 语法 | 例子 | 等价于 |
---|---|---|---|
等于 | {< key>:< value>} | db.test.find({“by”:”test.com”}).pretty() | where by = ‘test.com’ |
小于 | {< key>:{$lt:< value>}} | db.test.find({“likes”:{$lt:50}}).pretty() | where likes < 50 |
小于等于 | {< key>:{$lte:< value>}} | db.test.find({“likes”:{$lte:50}}).pretty() | where likes <= 50 |
大于 | {< key>:{$gt:< value>}} | db.test.find({“likes”:{$gt:50}}).pretty() | where likes > 50 |
大于等于 | {< key>:{$gte:< value>}} | db.test.find({“likes”:{$gte:50}}).pretty() | where likes >= 50 |
不等于 | {< key>:{$ne:< value>}} | db.test.find({“likes”:{$ne:50}}).pretty() | where likes != 50 |
以之前插入的50条数据为例:
- 查找书本价格等于51元的数据
> db.getCollection('books').find({price:51})
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7ad"),
"name" : "《朝花夕拾》",
"price" : 51.0,
"info" : "测试数据1",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.112Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.112Z")
}
- 查找书本价格大于80元的数据
db.getCollection('books').find({price:{$gt:80}})
其余的不再赘述
4.1.1、find中使用AND
语法
> db.qikegu.find(
{
$and: [
{key1: value1}, {key2:value2}
]
}
).pretty()
$and也可以省略:
> db.qikegu.find(
{
key1: value1,
key2: value2
}
).pretty()
示例
- 查询内容是测试数据10并且价格是60元的书本数据
> db.getCollection('books').find(
{
info:'测试数据10',
price:60
}
)
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7b6"),
"name" : "《朝花夕拾》",
"price" : 60.0,
"info" : "测试数据10",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.122Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.122Z")
}
4.1.2、fing中使用OR
语法:
> db.qikegu.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
关键字不可以省略
示例:
- 查询书本价格是60元或者价格是80元以上的书本数据
4.1.3、and和or一起使用
示例:
- 查询价格大于80的书本中简介是“测试数据22”或者简介是“测试数据22”
> db.getCollection('books').find(
{
price:{$gt:80},
$or:[
{info:'测试数据22'},
{info:'测试数据35'}
]}
)
// 结果
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7cf"),
"name" : "《朝花夕拾》",
"price" : 85.0,
"info" : "测试数据35",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.139Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.139Z")
}
五、更新文档
update()
基本语法:
> db.COLLECTION_NAME.update(SELECTION_CRITERIA, UPDATED_DATA)
参数1是查询条件,参数2是更新内容
示例1:
- 将书名是《朝花夕拾》并且简介是“测试数据1”的文档更新简介为“测试数据”
- 更新前
> db.books.update(
{name:'《朝花夕拾》', info:'测试数据1'},
{$set:{info:'测试数据'}}
)
更新后:
示例2:
- 我们需要将所有的书本简介都改为测试数据,但是update()方法默认配置multi为false,只修改匹配到的第一个文档,我们将其改成true即可
db.books.update(
{name:'《朝花夕拾》'},
{$set:{info:'测试数据'}},
{multi:true}
)
// 结果:
Updated 50 existing record(s) in 3ms
save()
基本语法:
> db.COLLECTION_NAME.save({_id:ObjectId(), NEW_DATA})
该方法就是之前所说的插入文档的另一种方法,特性也是一样的,给了具体id会覆盖该id的记录,哪怕是字段增加或者缺少,都会覆盖
六、删除文档
remove()方法
基本语法:
> db.COLLECTION_NAME.remove(DELLETION_CRITTERIA)
可以根据条件参数进行删除,如果条件为空,则删除该集合下的所有文档。如果只想删匹配到的第一个记录,则使用如下形式:
> db.COLLECTION_NAME.remove(DELETION_CRITERIA, 1)
示例:
- 删除价格为81元的书本数据
> db.books.remove(
{price:81}
)
- 删除价格在95元以上的书本数据
> db.books.remove(
{price:{$gt:95}}
)
Removed 4 record(s) in 1ms
- 删除价格在60以上的第一个文档
> db.books.remove(
{price:{$gt:60}},1
)
// 结果
Removed 1 record(s) in 1ms
七、投影/Projection和limit
Projection
上边说过了,find里面可以加查询条件,但是官方文档解释了,find可以接收第二个参数,该参数是一组字段列表,可以将我们想要显示出来的字段设置为1,不想显示出来的设置为0,但是除了_id以外,其他的要么全为1要么全为0,否则就报错
示例:
- 查询出来的文档不显示_id
> db.books.find({}, {_id:0, name:1, info:1, price:1, publish:1, createTime:1, updateTime:1})
- 报错情况
> db.books.find({}, {_id:0, name:1, info:0, price:1, publish:1, createTime:1, updateTime:1})
Error: error: {
"ok" : 0,
"errmsg" : "Projection cannot have a mix of inclusion and exclusion.",
"code" : 2,
"codeName" : "BadValue"
}
limit
limit()仍然是使用在find()之后的,用来限制返回结果数,一般需要配合skip()实现分页。
示例:
- 显示所有文档的前十个
> db.books.find({}).limit(10)
skip
skip
除了limit()
方法之外,还有一个方法skip()
也接受number类型参数,用于跳过文档的数量。可以看出,Skip()
方法的作用类似MySQL Offset语句。
语法:
//Page 1
db.users.find().limit (10)
//Page 2,跳过前十个,从11开始取十个
db.users.find().skip(10).limit(10)
//Page 3
db.users.find().skip(20).limit(10)
........
但是这种方法会全表扫描,数据量大之后需要改方案
八、排序
MongoDB中对结果进行排序,可以使用sort()方法,该方法也是使用在find()后边,该方法接收一个包含字段列表及其排序顺序的参数,可以使用1和-1,1是升序,-1是降序
语法:
> db.COLLECTION_NAME.find().sort({KEY:1})
示例:
- 查询所有文档,根据时间降序显示结果
> db.books.find({}).sort({createTime:-1})
// 结果
/* 1 */
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7d9"),
"name" : "《朝花夕拾》",
"price" : 95.0,
"info" : "测试数据",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.144Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.144Z")
}
/* 2 */
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7d7"),
"name" : "《朝花夕拾》",
"price" : 93.0,
"info" : "测试数据",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.143Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.143Z")
}
/* 3 */
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7d8"),
"name" : "《朝花夕拾》",
"price" : 94.0,
"info" : "测试数据",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.143Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.143Z")
}
/* 4 */
{
"_id" : ObjectId("5fb616a90c9ddf4e0db0d7d4"),
"name" : "《朝花夕拾》",
"price" : 90.0,
"info" : "测试数据",
"publish" : "人民出版社",
"createTime" : ISODate("2020-11-19T06:54:33.142Z"),
"updateTime" : ISODate("2020-11-19T06:54:33.142Z")
}
...
九、索引
shell中要创建索引,可以使用ensureIndex()
基本语法:
> db.COLLECTION_NAME.ensureIndex({KEY:1})
1表示按照升序创建索引,-1则是降序创建索引
示例:
- 以price和createTime升序创建多字段索引
> db.books.ensureIndex({price:1, createTime:1})
十、高级聚合操作
SQL 操作/函数 | mongodb聚合操作 |
---|---|
where | $match |
group by | $group |
having | $match |
select | $project |
order by | $sort |
limit | $limit |
sum() | $sum |
count() | $sum |
join | $lookup (v3.2 新增) |
聚合、联表见详情