初始
什么是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 所在位置
1
| 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:显示数据库中有多少个集合
增删改查
数据库操作
创建数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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
|
删除数据库
1 2
| db.dropDatabase() # 删除当前数据库,默认为 test,你可以使用 db 命令查看当前数据库名。
|
集合操作
创建集合
语法格式:
1
| db.createCollection(name, options)
|
参数说明:
- name: 要创建的集合名称
- options: 可选参数, 指定有关内存大小及索引的选项
1 2 3
| # 创建goods集合 > db.createCollection("goods") { "ok" : 1 }
|
创建固定集合 mycol
,整个集合空间大小 6142800 KB, 文档最大个数为 10000 个。
1 2 3 4
| > db.createCollection("mycol", { capped : true, autoIndexId : true, size : 6142800, max : 10000 } ) { "ok" : 1 } >
|
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
1 2 3 4
| > db.mycol2.insert({"name" : "菜鸟教程"}) > show collections mycol2 ...
|
删除集合
1 2 3 4 5 6 7 8
| # 举例 > show collections test user > db.test.drop() true > show collections user
|
文档操作
介绍
文档的数据结构和 JSON 基本一样。
所有存储在集合中的数据都是 BSON 格式。
BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。
插入文档
1 2 3 4 5 6 7
| insert:插入一个或多个
插入一个 db.user.insert({name:"zhangsan",age:20})
插入多个(使用中括号[]) db.goods.insert([{name:"apple",price:5},{name:"computer",price:6999}])
|
1 2 3 4 5 6 7
| insertOne:插入一个
> db.user.insertOne({name:"zhangsan",age:32}) { "acknowledged" : true, "insertedId" : ObjectId("6039dc6c9b01016868fc8027") }
|
1 2 3
| insertMany:插入多个
db.goods.insertMany([{name:"chair",price:49},{name:"computer",price:6999}])
|
1 2 3 4 5 6 7
| >db.col.insert({title: 'MongoDB 教程', description: 'MongoDB 是一个 Nosql 数据库', by: '菜鸟教程', url: 'http://www.runoob.com', tags: ['mongodb', 'database', 'NoSQL'], likes: 100 })
|
更新文档
1 2 3 4 5 6 7 8 9 10
| # 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 :可选,抛出异常的级别。
1 2 3 4 5
| # 例如:(将标题为“MongoDB 教程”改为“MongoDB”) db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
# 以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| # 将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 }
|
删除文档
1 2 3 4 5 6 7 8
| # remove语句基本语法 db.collection.remove( <query>, { justOne: <boolean>, writeConcern: <document> } )
|
参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别。
1 2 3 4 5
| # 将所有name为“apple”的文档删除 db.goods.remove({name:"apple"})
# 如果你只想删除第一条找到的记录可以设置 justOne 为 1 db.goods.remove({name:"apple"},1)
|
- 现在官方推荐使用 deleteOne() 和 deleteMany() 方法
1 2 3 4 5 6 7 8
| # 删除goods集合下所有文档 db.goods.deleteMany({})
# 删除name等于apple的全部文档 db.goods.deleteMany({name:"apple"})
# 删除name等于zhangsan的一个文档 db.user.deleteOne({name:"zhangsan"})
|
查询
查询文档
1
| db.collection.find(query, projection)
|
- query :可选,使用查询操作符指定查询条件
- projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
1 2 3 4 5
| # 查询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 |
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件
1 2 3
| db.col.find({key1:value1, key2:value2}).pretty()
db.goods.find({name:"computer",price:{$gte:6000}}).pretty()
|
MongoDB OR 条件语句使用了关键字 $or
查询键 by 值为 菜鸟教程 或键 title 值为 MongoDB 教程 的文档
1
| db.col.find({$or:[{"by":"菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
|
以下实例演示了 AND 和 OR 联合使用,类似常规 SQL 语句为: ‘where likes>50 AND (by = ‘菜鸟教程’ OR title = ‘MongoDB 教程’)’
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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 包含”教”字的文档:
1
| db.col.find({title:/教/})
|
查询 title 字段以”教”字开头的文档:
1
| db.col.find({title:/^教/})
|
查询 titl e字段以”教”字结尾的文档:
1
| db.col.find({title:/教$/})
|
分页查询
1 2
| # 返回指定NUMBER数量的数据记录 db.COLLECTION_NAME.find().limit(NUMBER)
|
排序
- 在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列
1 2 3 4 5 6 7 8
| >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(*)
1
| db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| > 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语句:
1
| select by_user, count(*) from mycol group by by_user
|
在上面的例子中,我们通过字段 by_user 字段对数据进行分组,并计算 by_user 字段相同值的总和。
表达式 |
描述 |
实例 |
$sum |
计算总和。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$sum : “$likes”}}}]) |
$avg |
计算平均值 |
db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$avg : “$likes”}}}]) |
$min |
获取集合中所有文档对应值得最小值。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$min : “$likes”}}}]) |
$max |
获取集合中所有文档对应值得最大值。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, num_tutorial : {$max : “$likes”}}}]) |
$push |
在结果文档中插入值到一个数组中。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$push: “$url”}}}]) |
$addToSet |
在结果文档中插入值到一个数组中,但不创建副本。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, url : {$addToSet : “$url”}}}]) |
$first |
根据资源文档的排序获取第一个文档数据。 |
db.mycol.aggregate([{$group : {_id : “$by_user”, first_url : {$first : “$url”}}}]) |
$last |
根据资源文档的排序获取最后一个文档数据 |
db.mycol.aggregate([{$group : {_id : “$by_user”, last_url : {$last : “$url”}}}]) |
SpringBoot集成
环境配置
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
|
1 2
| spring.data.mongodb.uri=mongodb://localhost:27017/recruit
|
实战应用
文章模块
普通的增删改查方法可以直接调用mongoTemplate的默认方法,自定义方法则需在接口主动声明。
1 2 3 4 5 6 7 8 9 10
| public interface ArticleRepository extends MongoRepository<Article, String> {
List<Article> findByModuleName(String moduleName);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| @Service public class ArticleServiceImpl implements ArticleService {
@Autowired private ArticleRepository articleRepository;
@Autowired private MongoTemplate mongoTemplate;
@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); }
@Override public ResultInfo<List<Article>> findByModuleName(String moduleName) { List<Article> articles = articleRepository.findByModuleName(moduleName); return ResultInfo.success(CodeEnum.SUCCESS, articles); }
@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); } }
|
题目模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| @Validated @Service public class QuestionServiceImpl implements QuestionService {
@Autowired private QuestionRepository questionRepository;
@Autowired private MongoTemplate mongoTemplate;
@Override public void saveOne(Question question) { questionRepository.save(question); }
@Override public ResultInfo<Question> getOneQuestion(){ List<Question> questions = new LinkedList<>(); 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)); } }
@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)); } }
@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安装
1 2 3 4 5 6 7 8 9
| 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")
|