目录
一.MongoDB基础
1.概念
MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。
2.存储结构
MongoDB将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB文档类似于JSON 对象。字段值可以包含其他文档,数组及文档数组。
3.特点
(1)索引数据结构为: B-tree 。
(2)支持索引和次级索引(secondary indexes): 次级索引是指文档或row有一个主键( primarykey )作为索引,同时允许文档或row内部还拥有一个索引,提升查询的效率。
4.MongoDB的基本概念(数据库、集合、文档)
下面看下mongodb中的概念与传统数据的比对吧
二.MongoDB语法
1.数据库
(1)概念:一个mongoDB的实例可以运行多个database,database之间是完全独立的,每个database有自己的权限,每个database存储于磁盘的不同文件。
(2)操作:
查看数据库列表
show dbs;
显示当前数据库
db
创建数据库
MongoDB 使用 use 命令创建数据库,如果数据库不存在,MongoDB 会在第一次使用该数据库时创建数据库。如果数据库已经存在则连接数据库,然后可以在该数据库进行各种操作。
use testdb;
注意: 在 MongoDB 中,只有在数据库中插入集合后才会创建! 就是说,创建数据库后要再插入一个集合,数据库才会真正创建。
插入数据
db.testdb.insertOne({"name":"张三"});
删除数据库
use testdb;
db;
#删除数据库
db.dropDatabase();
2.集合
(1)概念:相当于关系数据库的表,不过没有数据结构的定义。它由多个document组成。
(2)操作:
创建集合
可以通过 db.createCollection(name,option) 创建集合
name: 要创建的集合名称
options: 可选参数, 指定有关内存大小及索引的选项
举例:db.createCollection("blog"); //创建一个blog的集合
查看集合
show collections;
show tables;
删除集合
db.collection.drop()
collection为集合名称
举例:db.blog.drop()
3.文档
(1)概念: mongoDB的基本单位,相当于关系数据库中的行,它是一组有序的key/value键值对,使用json格式,如:{"foo" : 3, "greeting": "Hello, world!"}。
(2) 基础操作
插入数据
1.单条数据插入
insertOne(推荐)
db.blog.insertOne({
"title": "MySql 教程",
"description": "Mysql是一个传统数据库",
"by": "我的博客",
"url": "http://www.baiyp.ren",
"tags": [
"Mysql",
"database"
],
"likes": 10000
});
2.批量插入
insertMany(推荐)
db.blog.insertOne([
{
"title": "MySql 教程1",
"description": "Mysql是一个传统数据库2",
"by": "我的博客",
"url": "http://www.baiyp.ren",
"tags": [
"Mysql",
"database"
],
"likes": 10000
},
{
"title": "MySql 教程2",
"description": "Mysql是一个传统数据库2",
"by": "我的博客",
"url": "http://www.baiyp.ren",
"tags": [
"Mysql",
"database"
],
"likes": 10000
},
]);
查询文档
//查询所有
db.blog.find();
//美化查询结果
db.blog.find().pretty();
//只查询第一个文档
db.blog.findOne();
//等值查询
db.blog.find({
"title": "MySql 教程2"
}).pretty();
//投影查询如下
//只显示title列的数据
db.blog.find({"title":"MySql 教程2"},{"title":1}).pretty();
//只显示title和description列的数据
db.blog.find({"title":"MySql 教程2"},{"title":1,"description":1}).pretty();
//不显示 title和description列的数据
db.blog.find({"title":"MySql 教程2"},{"title":0,"description":0}).pretty();
更新文档
//根据id更新
db.blog.update({"_id":"1"},{$set:{"likes":666}})
//save更新
//save() 方法通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插入
db.blog.save({
"_id": "1",
"title": "MySql 传统教程教程3",
"description": "Mysql是一个传统数据库",
"by": "我的博客",
"url": "http://www.baiyp.ren",
"tags": [
"Mysql",
"database"
],
"likes": 100000
});
删除文档
//删除指定文档
db.blog.remove({"_id":"1"});
//删除复合条件的第一个文档
db.blog.deleteOne({});
//删除全部文档
db.blog.remove({});
//删除复合条件的所有文档
db.blog.deleteMany({});
三.MongoDB高级查询
1.关系表达式
(1)等于
等于的操作符是 $eq ,我们可以查询城市名称是 CUSHMAN 的数据
db.zips.find({
"city": {
"$eq": "CUSHMAN"
}
}).pretty();
(2)小于
小于的操作符号是 $lt ,我们查询城市人数小于 10万的城市有哪些
db.zips.find({
"pop": {
"$lt": 10
}
}).pretty();
(3)小于等于
小于等于的操作符号是 $lte ,我们查询城市没有人的城市,也就是小于等于0的城市
db.zips.find({
"pop": {
"$lte": 0
}
}).pretty();
(4)不等于
不等于的操作符号是 $ne ,我们可以搜索城市人数不是0的城市
db.zips.find({
"pop": {
"$ne": 0
}
}).pretty();
(5)包含查询
IN查询的符号是 $in ,使用方式如下
db.zips.find({
"state": {
"$in": [
"MA",
"NY"
]
}
}).pretty();
(6)不包含查询
NIN相当于MySQL的 NOT IN 查询,操作符号是 $nin ,我们查询城市名称缩写不是 MA 以及 NY 的文档
db.zips.find({
"state": {
"$nin": [
"MA",
"NY"
]
}
}).pretty();
(7)判断字段存在
mongodb是一个文档型数据库,对于表结构没有严格定义,有时候可能缺少字段,如果要查询缺失的字段可以使用 $exists 判断字段是否存在
db.zips.find({
"state": {
"$exists": false
}
}).pretty();
(8)多条件查询
db.zips.find({
"pop": {
"$gte": 10,
"$lt": 50
}
}).pretty();
2.逻辑表达式
(1)and
AND的标准写法的操作符是 $and ,下面是查询,我们查询 州缩写是 NY 并且人数大于一亿的文档。
db.zips.find({
"$and": [
{
"state": "NY"
},
{
"pop": {
"$gt": 100000
}
}
]
}).pretty();
(2)or
MongoDB OR 条件语句使用了关键字 $or,我们查询人数小于0 或者城市缩写是 NY 的城市。
db.zips.find({
"$or": [
{
"state": "NY"
},
{
"pop": {
"$lt": 0
}
}
]
}).pretty();
(3)not
$not 是NOT的操作符,和其他的用法不太一样,使用方法如下
查询人数 小于十万人的城市
db.zips.find({
"pop": {
"$not": {
"$gte": 10
}
}
}).pretty();
(4)多个条件表达式
实现如下sql的效果表达式举例
select * from zips where (state='NY' and pop>10 and pop <= 50) or (state
in('MD','VA') and pop>10 and pop <= 50)
db.zips.find({
"$or": [
{
"$and": [
{
"state": "NY"
},
{
"pop": {
"$gt": 10,
"$lte": 50
}
}
]
},
{
"$and": [
{
"state": {
"$in": [
"MD",
"VA"
]
}
},
{
"pop": {
"$gt": 10,
"$lte": 50
}
}
]
}
]
}).pretty();
3.排序
在MongoDB中使用sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1 和 -1 来指定排序的方式,其中 1 为升序排列,而-1是用于降序排列。
语法格式
db.COLLECTION_NAME.find().sort({KEY1:1,KEY2:-1,....});
(1)升序查询
按照城市人口升序查询
db.zips.find().sort({
"pop": 1
}).pretty();
(2)降序查询
按照城市人口降序查询
db.zips.find().sort({
"pop": -1
}).pretty();
(3)组合查询
我们查询人数大于1000万,并且先按照城市缩写升序排,如果城市缩写相同再按照人数降序排
db.zips.find({
"pop": {
"$gt": 1000
}
}).sort({
"state": 1,
"pop": -1
}).pretty();
4.分页查询
MongoDB提供了skip()和limit()方法。
skip: 跳过指定数量的数据. 可以用来跳过当前页之前的数据,即跳过pageSize*(n-1)。
limit: 指定从MongoDB中读取的记录条数,可以当做页面大小pageSize。
根据id排序查询前30条的数据
db.zips.find({},{"_id":1}).limit(30);
分页语句
#第一页数据
db.zips.find({},{_id:1}).sort({"_id":1}).limit(10);
# 第二页数据
db.zips.find({"_id":{$gt:"20"}},{_id:1}).sort({"_id":1}).limit(10);
# 第三页数据
db.zips.find({"_id":{$gt:"30"}},{_id:1}).sort({"_id":1}).limit(10);
5.统计
(1)count
查询记录的总数,下面条件是查询人数小于十万人的城市的数量
//写法1
db.zips.find({
"pop": {
"$not": {
"$gte": 10
}
}
}).count();
//写法2
db.zips.count({
"pop": {
"$not": {
"$gte": 10
}
}
});
(2)distinct
按照state字段进行去重后的数据
db.zips.distinct("state");
有条件去重:对于城市人数是七千万以上的城市的缩写去重
db.zips.distinct("state",{
"pop": {
"$gt": 70000
}
});
四.MongoDB索引
1.简介
在创建集合期间,MongoDB 在 _id 字段上 创建唯一索引,该索引可防止客户端插入两个具有相同值的文档。
2.查看索引
//查看集合索引
db.zips.getIndexes();
//查看数据库中所有集合的所有索引,需在 MongoDB 的 Shell 客户端执行以下语句
db.getCollectionNames().forEach(function(collection){
indexes = db[collection].getIndexes();
print("Indexes for [" + collection + "]:" );
printjson(indexes);
});
3.创建索引
就根据 pop 字段创建了一个升序索引
db.zips.createIndex({"pop":1})
//创建一个名称是 pop_union_index 的索引,按照 pop 字段降序,并且在5秒后删除
db.zips.createIndex(
{
"pop":-1 //降序
},
{
"name":"pop_union_index", //索引名称
"expireAfterSeconds":5 //TTL时间 5s后删除
}
)
4.删除索引
//根据索引的名字进行索引删除
db.zips.dropIndex("date_expire")
//根据字段进行删除索引
db.zips.dropIndex ({ "pop" : 1 })
//db.collection.dropIndexes() 可以把集合所有索引删除
db.zips.dropIndexes()
5.查看执行计划
db.zips.find({
"pop": {
"$gt": 10000
}
}).explain();
6.复合索引的创建
创建一个以 city 升序, state 降序的复合索引
db.zips.createIndex({
"city": 1,
"state": -1
})
在MySQL中存在最佳左前缀法则,在mongodb中查询同样生效
五.Springboot整合MongoDB
1.引入pom坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2.修改配置文件
spring:
application:
name: spring-boot-test
data:
mongodb:
database: test
host: 127.0.0.1
port: 27017
3.定义实体类映射mongo的集合
package com.itheima.mongo.domain;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @author tangbb
* @date 2022/9/14
*/
@Document
public class Blog {
@Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
4.定义查询方法
package com.itheima.mongo.controller;
import com.itheima.mongo.domain.Blog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author tangbb
* @date 2022/9/14
*/
@RestController
@RequestMapping("/mongo")
public class MongoDemoController {
@Autowired
private MongoTemplate mongoTemplate;
@RequestMapping("/{id}")
@ResponseBody
public String getBlogInfo(@PathVariable("id") String id) {
Blog blog = mongoTemplate.findById(id, Blog.class);
return blog.toString();
}
}
5.测试
//1.造数据
use test;
db.blog.insertOne({"name":"张三"});
db.blog.insertOne({"name":"李四"});
//2.浏览器访问如下接口
http://localhost:8899/mongo/63218413a83100003a0015cb