初始
什么是MongoDB
MongoDB 是一个基于分布式文件存储的数据库。
MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。

与MySQL相比的优势
1、弱一致性(最终一致),更能保证用户的访问速度
2、文档结构的存储方式,高扩展性
高扩展性,存储的数据格式是json格式
3、第三方支持丰富
4、性能优越
MySQL在海量数据处理的时候效率会显著变慢。
在适量级的内存的Mongodb的性能是非常迅速的,它将热数据存储在物理内存中,使得热数据的读写变得十分快。
缺点
1、不支持事务操作
2、占用空间过大
安装下载
下载地址:https://www.mongodb.com/try/download/community
配置
在data目录下创建db文件夹,在mongodb的bin目录下打开cmd输入命令 mongod -dbpath 所在位置
D:\Environment\MongoDB\bin>mongod -dbpath D:\Environment\MongoDB\data\db
启动运行
启动
1、cmd输入命令 net start mongodb
2、启动mongo.exe
基本命令
show dbs :显示当前所有数据库
use 数据库 :进入到指定数据库(不管有没有该数据库,都可以进入,若插入了文档,便会创建该数据库)
db:当前所处数据库
show collections:显示数据库中有多少个集合
增删改查
数据库操作
创建数据库
use DATABASE_NAME
# 如果数据库不存在,则创建数据库,否则切换到指定数据库
# 或者插入时创建数据库
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.test.insert({"name":"Kim"})
WriteResult({ "nInserted" : 1 })
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
test 0.000GB
删除数据库
db.dropDatabase()
# 删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。
集合操作
创建集合
语法格式:
db.createCollection(name, options)
参数说明:
- name: 要创建的集合名称
- options: 可选参数, 指定有关内存大小及索引的选项
# 创建goods集合
> db.createCollection("goods")
{ "ok" : 1 }
- 使用options
创建固定集合 mycol
,整个集合空间大小 6142800 KB, 文档最大个数为 10000 个。
> db.createCollection("mycol", { capped : true, autoIndexId : true, size :
6142800, max : 10000 } )
{ "ok" : 1 }
>
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
> db.mycol2.insert({"name" : "菜鸟教程"})
> show collections
mycol2
...
删除集合
db.collection.drop()
# 举例
> show collections
test
user
> db.test.drop()
true
> show collections
user
文档操作
介绍
文档的数据结构和 JSON 基本一样。
所有存储在集合中的数据都是 BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
插入文档
insert:插入一个或多个
插入一个
db.user.insert({name:"zhangsan",age:20})
插入多个(使用中括号[])
db.goods.insert([{name:"apple",price:5},{name:"computer",price:6999}])
insertOne:插入一个
> db.user.insertOne({name:"zhangsan",age:32})
{
"acknowledged" : true,
"insertedId" : ObjectId("6039dc6c9b01016868fc8027")
}
insertMany:插入多个
db.goods.insertMany([{name:"chair",price:49},{name:"computer",price:6999}])
- 实例
>db.col.insert({title: 'MongoDB 教程',
description: 'MongoDB 是一个 Nosql 数据库',
by: '菜鸟教程',
url: 'http://www.runoob.com',
tags: ['mongodb', 'database', 'NoSQL'],
likes: 100
})
更新文档
# update语句基本语法
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如 , , ,inc…)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
# 例如:(将标题为“MongoDB 教程”改为“MongoDB”)
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
# 以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
- 综合实例
# 将goods集合中name为"apple"的修改为"food"(只修改第一条发现的文档)
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }
> db.goods.update({name:"apple"},{$set:{name:"food"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }
> db.goods.update({name:"apple"},{$set:{name:"food"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "food", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }
# 将goods集合中所有name为"food"的修改为"apple"(修改多条相同的文档,则需要设置 multi 参数为 true)
> db.goods.update({name:"food"},{$set:{name:"apple"}},{multi:true})
WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
> db.goods.find()
{ "_id" : ObjectId("5fcb0237be45c9df825a5558"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0317be45c9df825a5559"), "name" : "chair", "price" : 49 }
{ "_id" : ObjectId("5fcb0317be45c9df825a555a"), "name" : "computer", "price" : 6999 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555b"), "name" : "apple", "price" : 5 }
{ "_id" : ObjectId("5fcb0346be45c9df825a555c"), "name" : "computer", "price" : 6999 }
删除文档
# remove语句基本语法
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别。
# 将所有name为“apple”的文档删除
db.goods.remove({name:"apple"})
# 如果你只想删除第一条找到的记录可以设置 justOne 为 1
db.goods.remove({name:"apple"},1)
- 现在官方推荐使用 deleteOne() 和 deleteMany() 方法
# 删除goods集合下所有文档
db.goods.deleteMany({})
# 删除name等于apple的全部文档
db.goods.deleteMany({name:"apple"})
# 删除name等于zhangsan的一个文档
db.user.deleteOne({name:"zhangsan"})
查询
查询文档
db.collection.find(query, projection)
- query :可选,使用查询操作符指定查询条件
- projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
# 查询user集合中的所有文档
db.user.find()
# pretty()方法以格式化的方式来显示所有文档
db.col.find().pretty()
- MongoDB 与 RDBMS Where 语句比较
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value> } | db.col.find({"by":"菜鸟教程"}).pretty() | where by = '菜鸟教程' |
小于 | {<key>:{$lt:<value>}} | db.col.find({"likes":{$lt:50}}).pretty() | where likes < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.col.find({"likes":{$lte:50}}).pretty() | where likes <= 50 |
大于 | {<key>:{$gt:<value>}} | db.col.find({"likes":{$gt:50}}).pretty() | where likes > 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.col.find({"likes":{$gte:50}}).pretty() | where likes >= 50 |
不等于 | {<key>:{$ne:<value>}} | db.col.find({"likes":{$ne:50}}).pretty() | where likes != 50 |
- and条件
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件
db.col.find({key1:value1, key2:value2}).pretty()
db.goods.find({name:"computer",price:{$gte:6000}}).pretty()
- or条件
MongoDB OR 条件语句使用了关键字 $or
查询键 by 值为 菜鸟教程 或键 title 值为 MongoDB 教程 的文档
db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
- AND 和 OR 联合使用
以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: 'where likes>50 AND (by = ‘菜鸟教程’ OR title = ‘MongoDB 教程’)'
db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
db.goods.find({name:"computer",$or:[{price:{$gte:6000}},{price:4999}]}).pretty()
{
"_id" : ObjectId("6039dba49b01016868fc8026"),
"name" : "computer",
"price" : 6999
}
{
"_id" : ObjectId("603a00f19b01016868fc802b"),
"name" : "computer",
"price" : 4999
}
模糊查询
查询 title 包含"教"字的文档:
db.col.find({title:/教/})
查询 title 字段以"教"字开头的文档:
db.col.find({title:/^教/})
查询 titl e字段以"教"字结尾的文档:
db.col.find({title:/教$/})
分页查询
# 返回指定NUMBER数量的数据记录
db.COLLECTION_NAME.find().limit(NUMBER)
排序
- 在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列
>db.COLLECTION_NAME.find().sort({KEY:1})
# 按价格 升序 排序
> db.goods.find().sort({price:1})
{ "_id" : ObjectId("6039e2589b01016868fc8029"), "name" : "box" }
{ "_id" : ObjectId("603a00f19b01016868fc802a"), "name" : "chair", "price" : 90 }
{ "_id" : ObjectId("603a00f19b01016868fc802b"), "name" : "computer", "price" : 4999 }
{ "_id" : ObjectId("6039dba49b01016868fc8026"), "name" : "computer", "price" : 6999 }
- skip(),limilt(),sort()三个放在一起执行的时候,执行的顺序是先 sort(),然后是 skip(),最后是显示的 limit()
聚合
MongoDB 中聚合(aggregate)主要用于处理数据(诸如统计平均值,求和等),并返回计算后的数据结果。
有点类似 SQL 语句中的 count(*)
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
> db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : 1}}}])
{
"result" : [
{
"_id" : "runoob.com",
"num_tutorial" : 2
},
{
"_id" : "Neo4j",
"num_tutorial" : 1
}
],
"ok" : 1
}
>
以上实例类似sql语句:
select by_user, count(*) from mycol group by by_user
在上面的例子中,我们通过字段 by_user 字段对数据进行分组,并计算 by_user 字段相同值的总和。
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { s u m : " sum : " sum:"likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { a v g : " avg : " avg:"likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m i n : " min : " min:"likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", num_tutorial : { m a x : " max : " max:"likes"}}}]) |
$push | 在结果文档中插入值到一个数组中。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { p u s h : " push: " push:"url"}}}]) |
$addToSet | 在结果文档中插入值到一个数组中,但不创建副本。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", url : { a d d T o S e t : " addToSet : " addToSet:"url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", first_url : { f i r s t : " first : " first:"url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{KaTeX parse error: Expected '}', got 'EOF' at end of input: …roup : {_id : "by_user", last_url : { l a s t : " last : " last:"url"}}}]) |
SpringBoot集成
环境配置
<!--引入mongodb-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
# 配置mongodb
spring.data.mongodb.uri=mongodb://localhost:27017/recruit
实战应用
文章模块
- dao层
普通的增删改查方法可以直接调用mongoTemplate的默认方法,自定义方法则需在接口主动声明。
public interface ArticleRepository extends MongoRepository<Article, String> {
/**
* 根据模块名查找文章
* @param moduleName
* @return
*/
List<Article> findByModuleName(String moduleName);
}
- service层
@Service
public class ArticleServiceImpl implements ArticleService {
@Autowired
private ArticleRepository articleRepository;
@Autowired
private MongoTemplate mongoTemplate;
/**
* 获取默认文章(4个)
* @return
*/
@Override
public ResultInfo<List<Article>> findDefaultArticle() {
Query query = new Query();
Sort sort = Sort.by("gmtCreate").descending();
PageRequest pageRequest = PageRequest.of(0, 4);
query.with(sort);
query.with(pageRequest);
List<Article> articleList = mongoTemplate.find(query, Article.class);
return ResultInfo.success(CodeEnum.SUCCESS, articleList);
}
/**
* 根据模块名查找文章
* @param moduleName
* @return
*/
@Override
public ResultInfo<List<Article>> findByModuleName(String moduleName) {
List<Article> articles = articleRepository.findByModuleName(moduleName);
return ResultInfo.success(CodeEnum.SUCCESS, articles);
}
/**
* 根据文章标题模糊查询
* @param articleTitle
* @return
*/
@Override
public ResultInfo<List<Article>> findByArticleTitle(String articleTitle) {
Pattern pattern =
Pattern.compile("^.*" + articleTitle + ".*$", Pattern.CASE_INSENSITIVE);
Query query = new Query();
query.addCriteria(Criteria.where("articleTitle").regex(pattern));
Sort sort = Sort.by("gmtCreate").descending();
query.with(sort);
List<Article> articles = mongoTemplate.find(query, Article.class);
return ResultInfo.success(CodeEnum.SUCCESS, articles);
}
}
题目模块
@Validated
@Service
public class QuestionServiceImpl implements QuestionService {
@Autowired
private QuestionRepository questionRepository;
@Autowired
private MongoTemplate mongoTemplate;
/**
* 新增一道题目
* @param question
*/
@Override
public void saveOne(Question question) {
questionRepository.save(question);
}
/**
* 自由模式随机查找一道题
* @return
*/
@Override
public ResultInfo<Question> getOneQuestion(){
List<Question> questions = new LinkedList<>();
// Aggregation.sample()可随机抽选指定数量的数据
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, Aggregation.sample(1));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
if(questions.isEmpty()){
return ResultInfo.error(CodeEnum.PARAM_NOT_IDEAL, null);
}else{
return ResultInfo.success(CodeEnum.SUCCESS, questions.get(0));
}
}
/**
* 自由模式根据模块名随机查找一道题
* @param moduleName
* @return
*/
@Override
public ResultInfo<Question> getOneQuestionByName(@NotBlank String moduleName){
List<Question> questions = new LinkedList<>();
MatchOperation match =
Aggregation.match(Criteria.where("moduleName").is(moduleName));
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, match, Aggregation.sample(1));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
if(questions.size() == 0){
return ResultInfo.error(CodeEnum.PARAM_NOT_IDEAL, null);
}else{
return ResultInfo.success(CodeEnum.SUCCESS, questions.get(0));
}
}
/**
* 闯关模式根据模块名随机查找10道题
* @param moduleName
* @return
*/
@Override
public ResultInfo<List<Question>> getQuestionsByName(@NotBlank String moduleName){
List<Question> questions = new LinkedList<>();
MatchOperation match =
Aggregation.match(Criteria.where("moduleName").is(moduleName));
TypedAggregation<Question> aggregation =
Aggregation.newAggregation(Question.class, match, Aggregation.sample(10));
AggregationResults<Question> results =
mongoTemplate.aggregate(aggregation, Question.class);
results.forEach(result->{
questions.add(result);
});
return ResultInfo.success(CodeEnum.SUCCESS, questions);
}
}
docker安装
docker pull mongo:4.4.1
docker run -p 27017:27017 --name mongo -v /home/mongo/db:/data/db -d mongo:4.4.1 --auth
docker exec -it mongo mongo #进入容器
use admin
> db.createUser({
... user: "KimTou",
... pwd: "123456",
... roles: [{ role:"root",db:"admin" }] });
> db.auth("KimTou","123456") # 测试