1. MongoDB简介
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。 MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。 MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。 官网:https://www.mongodb.com
2. 通过docker安装MongoDB(linux)
docker pull mongo:4.0.3
docker create --name mongodb-server -p 27018:27017 -v mongodb-data:/data/db mongo:4.0.3 --auth
docker start mongodb-server
docker exec -it mongodb-server /bin/bash
mongo
use admin
db.createUser( { user: 'root' , pwd: 'root' , roles: [ { role: "root" , db: "admin" } ] } )
> show dbs
2020-10-20T09:09:15.543+0000 E QUERY [ js] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "command listDatabases requires authentication" ,
"code" : 13,
"codeName" : "Unauthorized"
} :
mongo -u "root" -p "root" --authenticationDatabase "admin"
use admin
db.createUser( { user: 'tanhua' , pwd: 'l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV' , roles: [ { role: "readWrite" , db: "tanhua" } ] } ) ;
mongo -u "tanhua" -p "l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV" --authenticationDatabase "admin"
root@5d848955ff7e:/
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID( "6c368269-30f0-4b29-a224-05a38b5847e2" ) }
MongoDB server version: 4.0.3
> use tanhua
switched to db tanhua
> db.user.insert( { id:1,username:'zhangsan' ,age:20} )
WriteResult( { "nInserted" : 1 } )
> db.user.find( )
{ "_id" : ObjectId( "5f8eb2726e0de0aa9517afd3" ) , "id" : 1, "username" : "zhangsan" , "age" : 20 }
3. MongoDB基本操作
3.1 基本概念
为了更好的理解,下面与SQL中的概念进行对比:
SQL术语/概念 MongoDB术语/概念 解释/说明 database database 数据库 table collection 数据库表/集合 row document 数据记录行/文档 column field 数据字段/域 index index 索引 table joins 表连接,MongoDB不支持 primary key primary key 主键,MongoDB自动将_id字段设置为主键
3.2 数据库以及表的操作
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> use admin
switched to db admin
> use testdb
switched to db testdb
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
> db.user.insert( { id:1,name:'zhangsan' } )
WriteResult( { "nInserted" : 1 } )
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
testdb 0.000GB
> show tables
user
> show collections
user
>
> db.user.drop( )
true
> use testdb
switched to db testdb
> db.dropDatabase( )
{ "dropped" : "testdb" , "ok" : 1 }
> show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
3.3 新增数据
在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。
> db.user.insert( { id:1,username:'zhangsan' ,age:20} )
WriteResult( { "nInserted" : 1 } )
> db.user.save( { id:2,username:'lisi' ,age:25} )
WriteResult( { "nInserted" : 1 } )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "id" : 1, "username" : "zhangsan" , "age" : 20 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25 }
3.4 更新数据
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
:可选,抛出异常的级别。 实例
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "id" : 1, "username" : "zhangsan" , "age" : 20 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25 }
> db.user.update( { id:1} ,{ $set :{ age:22} } )
WriteResult( { "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 } )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "id" : 1, "username" : "zhangsan" , "age" : 22 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25 }
> db.user.update( { id:1} ,{ age:25} )
WriteResult( { "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 } )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "age" : 25 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25 }
> db.user.update( { id:2} ,{ $set :{ sex:1} } )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "age" : 25 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25, "sex" : 1 }
> db.user.update( { id:3} ,{ $set :{ sex:1} } )
WriteResult( { "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 } )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "age" : 25 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25, "sex" : 1 }
> db.user.update( { id:3} ,{ $set :{ sex:1} } ,true)
WriteResult( {
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId( "5c08cb281418d073246bc642" )
} )
> db.user.find( )
{ "_id" : ObjectId( "5c08c0024b318926e0c1f6dc" ) , "age" : 25 }
{ "_id" : ObjectId( "5c08c0134b318926e0c1f6dd" ) , "id" : 2, "username" : "lisi" , "age" : 25, "sex" : 1 }
{ "_id" : ObjectId( "5c08cb281418d073246bc642" ) , "id" : 3, "sex" : 1 }
3.5 删除数据
db.collection.remove(
< query> ,
{
justOne: < boolean> ,
writeConcern: < document>
}
)
参数说明:
query
:(可选)删除的文档的条件。justOne
: (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。writeConcern
:(可选)抛出异常的级别。 实例:
> db.user.remove( { age:25} )
WriteResult( { "nRemoved" : 2 } )
db.user.insert( { id:1,username:'zhangsan' ,age:20} )
db.user.insert( { id:2,username:'lisi' ,age:21} )
db.user.insert( { id:3,username:'wangwu' ,age:22} )
db.user.insert( { id:4,username:'zhaoliu' ,age:22} )
> db.user.remove( { age:22} ,true)
WriteResult( { "nRemoved" : 1 } )
> db.user.remove( { } )
db.user.deleteOne( { id:1} )
db.user.deleteMany( { } )
3.6 查询数据
db.user.find([query],[fields])
参数说明
query
:可选,使用查询操作符指定查询条件fields
:可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。 如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
>db.col.find().pretty()
pretty() 方法以格式化的方式来显示所有文档。 条件查询:
操作 格式 范例 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
实例:
db.user.insert( { id:1,username:'zhangsan' ,age:20} )
db.user.insert( { id:2,username:'lisi' ,age:21} )
db.user.insert( { id:3,username:'wangwu' ,age:22} )
db.user.insert( { id:4,username:'zhaoliu' ,age:22} )
db.user.find( )
db.user.find( { } ,{ id:1,username:1} )
db.user.find( ) .count( )
db.user.find( { id:1} )
db.user.find( { age:{ $lte :21} } )
db.user.find( { age:{ $lte :21} , id:{ $gte :2} } )
db.user.find( { $or :[ { id:1} ,{ id:2} ] } )
db.user.find( ) .limit( 2) .skip( 1)
db.user.find( ) .sort( { id:-1} )
4. 索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。 这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。 索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
> db.user.getIndexes( )
[
{
"v" : 2,
"key" : {
"_id" : 1
} ,
"name" : "_id_" ,
"ns" : "testdb.user"
}
]
> db.user.createIndex( { 'age' :1} )
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
db.user.dropIndex( "age_1" )
db.user.dropIndexes( )
db.user.createIndex( { 'age' :1, 'id' :-1} )
db.user.totalIndexSize( )
5. 执行计划
MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。
for( var i= 1; i< 1000; i++) db.user.insert( { id:100+i,username:'name_' +i,age:10+i} )
> db.user.find( { age:{ $gt :100} ,id:{ $lt :200} } ) .explain( )
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "testdb.user" ,
"indexFilterSet" : false,
"parsedQuery" : {
"$and " : [
{
"id" : {
"$lt " : 200
}
} ,
{
"age" : {
"$gt " : 100
}
}
]
} ,
"winningPlan" : {
"stage" : "FETCH" ,
"inputStage" : {
"stage" : "IXSCAN" ,
"keyPattern" : {
"age" : 1,
"id" : -1
} ,
"indexName" : "age_1_id_-1" ,
"isMultiKey" : false,
"multiKeyPaths" : {
"age" : [ ] ,
"id" : [ ]
} ,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward" ,
"indexBounds" : {
"age" : [
"(100.0, inf.0]"
] ,
"id" : [
"(200.0, -inf.0]"
]
}
}
} ,
"rejectedPlans" : [ ]
} ,
"serverInfo" : {
"host" : "c493d5ff750a" ,
"port" : 27017,
"version" : "4.0.3" ,
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
} ,
"ok" : 1
}
> db.user.find( { username:'zhangsan' } ) .explain( )
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "testdb.user" ,
"indexFilterSet" : false,
"parsedQuery" : {
"username" : {
"$eq " : "zhangsan"
}
} ,
"winningPlan" : {
"stage" : "COLLSCAN" ,
"filter" : {
"username" : {
"$eq " : "zhangsan"
}
} ,
"direction" : "forward"
} ,
"rejectedPlans" : [ ]
} ,
"serverInfo" : {
"host" : "c493d5ff750a" ,
"port" : 27017,
"version" : "4.0.3" ,
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
} ,
"ok" : 1
}
6. UI客户端工具
Robo 3T是MongoDB的客户端工具,我们可以使用它来操作MongoDB。 查看数据: 或使用Navicat Premium 15:
7. SpringBoot整合MongoDB
7.1 导入依赖
使用spring-data-mongodb可以简化MongoDB的操作。
<?xml version="1.0" encoding="UTF-8"?>
< project xmlns = " http://maven.apache.org/POM/4.0.0"
xmlns: xsi= " http://www.w3.org/2001/XMLSchema-instance"
xsi: schemaLocation= " http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
< modelVersion> 4.0.0</ modelVersion>
< parent>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-parent</ artifactId>
< version> 2.1.0.RELEASE</ version>
</ parent>
< groupId> cn.itcast.mongodb</ groupId>
< artifactId> itcast-mongodb</ artifactId>
< version> 1.0-SNAPSHOT</ version>
< dependencies>
< dependency>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-data-mongodb</ artifactId>
</ dependency>
< dependency>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-test</ artifactId>
< scope> test</ scope>
</ dependency>
< dependency>
< groupId> org.projectlombok</ groupId>
< artifactId> lombok</ artifactId>
< optional> true</ optional>
< version> 1.18.4</ version>
</ dependency>
</ dependencies>
< build>
< plugins>
< plugin>
< groupId> org.apache.maven.plugins</ groupId>
< artifactId> maven-compiler-plugin</ artifactId>
< version> 3.2</ version>
< configuration>
< source> 1.8</ source>
< target> 1.8</ target>
< encoding> UTF-8</ encoding>
</ configuration>
</ plugin>
</ plugins>
</ build>
</ project>
7.2 编写application.properties配置文件
# Spring boot application
spring.application.name = itcast-mongodb
#无认证信息的配置
#spring.data.mongodb.uri=mongodb://192.168.31.81:27017/tanhua
#springboot 配置
spring.data.mongodb.username=tanhua
spring.data.mongodb.password=l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=tanhua
spring.data.mongodb.port=27018
spring.data.mongodb.host=192.168.31.81
7.3 编写实体
package cn. itcast. mongodb. pojo;
import lombok. AllArgsConstructor;
import lombok. Data;
import lombok. NoArgsConstructor;
import org. bson. types. ObjectId;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
private ObjectId id;
private String name;
private int age;
private Address address;
}
package cn. itcast. mongodb. pojo;
import lombok. AllArgsConstructor;
import lombok. Data;
import lombok. NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
private String street;
private String city;
private String zip;
}
7.4 编写dao
package cn. itcast. mongodb. dao;
import cn. itcast. mongodb. pojo. Person;
import com. mongodb. client. result. DeleteResult;
import com. mongodb. client. result. UpdateResult;
import org. springframework. beans. factory. annotation. Autowired;
import org. springframework. data. mongodb. core. MongoTemplate;
import org. springframework. data. mongodb. core. query. Criteria;
import org. springframework. data. mongodb. core. query. Query;
import org. springframework. data. mongodb. core. query. Update;
import org. springframework. stereotype. Component;
import java. util. List;
@Component
public class PersonDao {
@Autowired
private MongoTemplate mongoTemplate;
public void savePerson ( Person person) {
this . mongoTemplate. save ( person) ;
}
public List< Person> queryPersonListByName ( String name) {
Query query = Query. query ( Criteria. where ( "name" ) . is ( name) ) ;
return this . mongoTemplate. find ( query, Person. class ) ;
}
public List< Person> queryPersonPageList ( Integer page, Integer rows) {
Query query = new Query ( ) . limit ( rows) . skip ( ( page - 1 ) * rows) ;
return this . mongoTemplate. find ( query, Person. class ) ;
}
public UpdateResult update ( Person person) {
Query query = Query. query ( Criteria. where ( "id" ) . is ( person. getId ( ) ) ) ;
Update update = Update. update ( "age" , person. getAge ( ) ) ;
return this . mongoTemplate. updateFirst ( query, update, Person. class ) ;
}
public DeleteResult deleteById ( String id) {
Query query = Query. query ( Criteria. where ( "id" ) . is ( id) ) ;
return this . mongoTemplate. remove ( query, Person. class ) ;
}
}
7.5 编写启动类
package cn. itcast. mongodb;
import org. springframework. boot. SpringApplication;
import org. springframework. boot. autoconfigure. SpringBootApplication;
@SpringBootApplication
public class MongoApplication {
public static void main ( String[ ] args) {
SpringApplication. run ( MongoApplication. class , args) ;
}
}
7.6 编写单元测试
package cn. itcast. mongodb;
import cn. itcast. mongodb. dao. PersonDao;
import cn. itcast. mongodb. pojo. Address;
import cn. itcast. mongodb. pojo. Person;
import org. bson. types. ObjectId;
import org. junit. Test;
import org. junit. runner. RunWith;
import org. springframework. beans. factory. annotation. Autowired;
import org. springframework. boot. test. context. SpringBootTest;
import org. springframework. test. context. junit4. SpringRunner;
import java. util. List;
@RunWith ( SpringRunner. class )
@SpringBootTest
public class TestPersonDao {
@Autowired
private PersonDao personDao;
@Test
public void testSave ( ) {
Person person = new Person ( ObjectId. get ( ) , "张三" , 20 ,
new Address ( "人民路" , "上海市" , "666666" ) ) ;
this . personDao. savePerson ( person) ;
}
@Test
public void testQuery ( ) {
List< Person> personList = this . personDao. queryPersonListByName ( "张三" ) ;
for ( Person person : personList) {
System. out. println ( person) ;
}
}
@Test
public void testQuery2 ( ) {
List< Person> personList = this . personDao. queryPersonPageList ( 2 , 2 ) ;
for ( Person person : personList) {
System. out. println ( person) ;
}
}
@Test
public void testUpdate ( ) {
Person person = new Person ( ) ;
person. setId ( new ObjectId ( "5c0956ce235e192520086736" ) ) ;
person. setAge ( 30 ) ;
this . personDao. update ( person) ;
}
@Test
public void testDelete ( ) {
this . personDao. deleteById ( "5c09ca05235e192d8887a389" ) ;
}
}