SQL | MongoDB |
---|---|
数据库(database) | 数据库(database) |
表(table) | 集合(collection) |
行row | 文档(document) |
列(column) | 字段(field) |
索引(index) | 索引(index) |
主键(primary key) | _id(字段) |
视图 (view) | 视图 (view) |
表连接(table joins) | 聚合操作 ($lookup) |
https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.26.tgz
命令1
进入bin目录,输入./mongo --help
查看帮助信息
命令2
指定data和log路径
启动mongoDB
bin/mongod --port=27017 --dbpath=/app/mongodb-linux-x86_64-rhel70-4.4.26/data --logpath=/app/mongodb-linux-x86_64-rhel70-4.4.26/log/mongodb.log --bind_ip=0.0.0.0 --fork
show dbs
2. 创建(切换)db
db.shutdownServer()
菜鸟教程更多
https://www.runoob.com/mongodb/mongodb-tutorial.html
systemLog:
destination: file
path: /app/mongodb-linux-x86_64-rhel70-4.4.26/log/mongodb.log #指定日志输入文件夹(绝对路径)
logAppend: true
storage:
dbPath: /app/mongodb-linux-x86_64-rhel70-4.4.26/data #指定数据输入文件夹(绝对路径)
engine: wiredTiger #存储引擎
journal:
enabled: true #是否启动journal日志
net:
bindIp: 0.0.0.0
port: 27017
processManagement:
fork: true
mongod -f /app/mongodb-linux-x86_64-rhel70-4.4.26/mongo.conf #启动配置文件绝对路径
进入bin目录输入./mongo
打开命令控制台
mongod -f /app/mongodb-linux-x86_64-rhel70-4.4.26/mongo.conf --shutdown ##配置文件绝对路径
数据库操作
#查看所有数据库
show dbs
#use 切换数据库(创建)
use demodb
#删除当前数据库
db.dropDatabase()
集合操作
#查看所有集合
show collections
#创建集合
db.createCollection("studenttable")
#删除集合
db.studenttable.drop()
#设置管理员用户密码需要在admin库
use admin
#创建管理员
db.createUser({user:"zmc",pwd:"123456",roles:["root"]})
#查看所有用户信息
show users
#删除用户
db.dropUser("zmc")
#验证用户
db.auth("zmc","123456")
权限名 | 描述 |
---|---|
read | 允许用户读取指定数据库 |
readWrite | 允许用户读写指定数据库 |
dbAdmin | 允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile |
dbowner | 允许用户在指定数据库中执行任意操作,增、删、改、查等 |
userAdmin | 允许用户向system.users集合写入,可以在指定数据库里创建、删除和管理用户 |
clusterAdmin | 只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限 |
readAnyDatabase | 只在admin数据库中可用,赋予用户所有数据库的读权限 |
readWriteAnvDatabase | 只在admin数据库中可用,赋予用户所有数据库的读写权限 |
userAdminAnyDatabase | 只在admin数据库中可用,赋予用户所有数据库的userAdmin权限 |
dbAdminAnyDatabase | 只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限 |
root | 只在admin数据库中可用。超级账号,超级权限 |
--auth
启动mongodbmongod -f /app/mongodb-linux-x86_64-rhel70-4.4.26/mongo.conf --auth
mongo -uzmc -p123456 --authenticationDatabase=admin
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
writeConcern 决定一个写操作落到多少个节点上才算成功。writeConcern 的取值包括
0:发起写操作,不关心是否成功;
1:集群最大数据节点数: 写操作需要被复制到指定节点数才算成功
majority: 写操作需要被复制到大多数节点上才算成功。
db.student_info.insertOne({name:"小明",age:41,sex:"男"})
db.student_info.insert({name:"李四",age:20,sex:"男"})
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
writeConcern: 写入策略,默认为 1,即要求确认写操作,0 是不要求
ordered:指定是否按顺序写入,默认 true,按顺序写入
insert和save也可以实现批量插入
db.student_info.insertMany([{name:"王五",age:21,sex:"女"},{name:"赵六",age:23,sex:"女"}])
let tags=["nosql","MongoDB","document","developer","popular"];
let types =["technology","sociality","travel","novel","literature"];
var books=[];
for(let i=0;i<60;i++){
let tagIndx=Math.floor(Math.random()*tags.length);
let tyIndx=Math.floor(Math.random()*types.length);
let favCount=Math.floor(Math.random()*120);
let book={
title:"book_"+(i+1),
type:types[tyIndx],
tag:tags[tagIndx],
favCount:favCount,
author:"zmc_"+(i+1)
};
books.push(book);
}
db.books.insertMany(books);
load("/app/mongodb-linux-x86_64-rhel70-4.4.26/js/book.js") #js文件的绝对路径
db.collection.find(query,projection)
query :可选,使用查询操作符指定查询条件相当于sql中的where
projection:可选,使用投影操作符指定返回的键(相当于返回sql表中指定的字段)。查询时返回文档中所有键值,只需省略该参数即可(默认省略)。投影时,id为1的时候,其他字段必须是1 ; id是0的时候,其他字段可以是0;如果没有_id字段约束,多个其他字段必须同为0或同为1。
例题
db.books.find({title:"book_2"})
db.books.find({title:"book_1",author:"zmc_1"})
db.books.find({type:"travel",tag:"document"},{title:1,type:1,tag:1})
同find一样,但是findOne只返回第一条数据
db.collection.findOne(query,projection)
db.books.findOne({type:"travel",tag:"document"},{title:1,type:1,tag:1})
SQL | MongoDB |
---|---|
filed=1 | {field:1} |
filed<>1 | {field:{$ne:1}} |
filed>1 | {field:{$gt:1}} |
filed>=1 | {field:{$gte:1}} |
filed<1 | {field:{$lt:1}} |
filed<=1 | {field:{$lte:1}} |
filed1=1 AND filed2=3 | {field1:1, filed2:3}或{$and:[{field1:1},{field2:3}]} |
filed1=1 OR filed2=3 | {$or:[{field1:1},{field2:3}]} |
filed IS NULL | {field:{$exists:false}} |
filed IN (1,2,3) | {field:{$in:[1,2,3]}} |
filed NOT IN (1,2,3) | {field:{$nin:[1,2,3]}} |
例:
#tag!=nosql 并且 type!=technology
db.books.find({tag:{$ne:"nosql"},type:{$ne:"technology"}})
#favCount>99
db.books.find({favCount:{$gt:99}})
#type=sociality 或者 tag=MongoDB
db.books.find({$or:[{type:"sociality"},{tag:"MongoDB"}]})
#查询不存在author字段的数据,如果author=null或author=""则查不到
db.books.find({author:{$exists:false}})
#tag IN ('nosql','popular','MongoDB',)
db.books.find({tag:{$in:["nosql","popular","MongoDB"]}})
#查询type=sociality或者tagMongoDB,再根据type正序排序favCount倒序排序
db.books.find({$or:[{type:"sociality"},{tag:"MongoDB"}]}).sort({type:1,favCount:-1})
#查询favCount>=60,再跳过前三条数据,限制为5条数据
db.books.find({favCount:{$gte:60}}).skip(3).limit(5)
#type包含ve,相当于sql的type like '%ve%'
db.books.find({type:{$regex:"ve"}})
也可以这样写
db.books.find({type:/ve/})
db.collection.update(query,update,options)
更新操作符
操作符 | 格式 | 描述 |
---|---|---|
$set | {$set:{field:value}} | 指定一个键并更新值,若键不存在则创建 |
$unset | {$unset:{field:1}} | 删除一个键 |
$inc | {$inc : {field : value } } | 对数值类型进行增减 |
$rename | {$rename :{old_field_name :new_field_name } } | 修改字段名称 |
$push | { $push : {field : value } } | 将数值追加到数组中,若数组不存在则会进行初始化 |
$pushAll | {$pushAll : {field : value_array}} | 追加多个值到一个数组字段内 |
$pull | {$pull : {field : _value } } | 从数组中删除指定的元素 |
$addToSet | {$addToSet : {field : value } } | 添加元素到数组中,具有排重功能 |
$pop | {$pop : {field : 1 }} | 删除数组的第一个或最后一个元素 |
#把type=travel的数据,favCount减去100
db.books.update({type:"travel"},{$inc:{favCount:-100}})
db.books.updateOne({type:"travel"},{$set:{createDate:"2133-12-23T11:48:22.913Z"}})
db.books.replaceOne({type:"travel"},{"title" : "book_116", "type" : "travel", "tag" : "developer", "favCount" : 81, "author" : "zmc_6", "createDate" : ISODate("2023-12-23T11:48:22.913Z")})
不可实现替换多个文档
#彻底替换整个文档
db.books.update({type:"zmc"},{oneField:12222})
需要配合使用multi,设置为true
#更新多行数据,并添加createDate字段(如果没有该字段,则新增该字段)
db.books.update({type:"travel"},{$set:{createDate:new Date()}},{multi:true})
db.books.updateMany({type:"travel"},{$set:{createDate:new Date()}})
db.books.update({type:"zmc"},{$set:{createDate:"2133-12-23T11:48:22.913Z",tag:[1,2,3]}},{upsert:true})
findAndModify只能更新单个文档
#先查询title=book_1的数据,再把该条数据的athor修改为zhangmengchao
db.books.findAndModify({query:{title:"book_1"},update:{$set:{author:"zhangmengchao"}}})
db.books.findAndModify({query:{title:"book_2"},update:{$set:{author:"zhangmengchao2"}},new:true})
与findAndModify语义相近的命令如下:
findOneAndUpdate:更新单个文档并返回史新前(或更新后)的文档。. findOneAndReplace:替换单个文档并返回替换前(或替换后的文档。
#删除type是sociality和novel并且favCount>=18的数据
db.books.remove({type:{$in:["sociality","novel"]},favCount:{$gte:18}})
满足条件的有17个全删了
#justOne为true,代表只删除一个文档
db.books.remove({type:"travel"},{justOne:true})
db.books.remove({})
#删除type=novel或者tag为MongoDB,并且favCount>100的一条数据
db.books.deleteOne({$or:[{type:"novel"},{tag:{$in:["MongoDB"]}}],favCount:{$gt:100}})
#删除type=novel或者tag为MongoDB,并且favCount>100的多条数据
db.books.deleteMany({$or:[{type:"novel"},{tag:{$in:["MongoDB"]}}],favCount:{$gt:100}})
删除所有文档
db.books.deleteMany({})
#删除author=zhangmengchao的文档
db.books.findOneAndDelete({"author" : "zhangmengchao"})
#查询出满足tag=popular的所有文档,再倒序排序。删除第一个文档
db.books.findOneAndDelete({"tag" : "popular"},{sort:{favCount:-1}})
remove、deleteOne等命令只能按默认顺序删除,利用这个特性, findOneAndDelete可以实现队列的先进先出。
https://downloads.mongodb.com/compass/mongodb-compass-1.41.0-win32-x64.exe
在Linux环境部署MongoDB需要开放MongoDB的端口
进入后的画面
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
data:
mongodb:
database: zmcdb
host: 192.168.0.104
port: 27017
username: zmc
password: '123456' #注意密码加单引号
authentication-database: admin
#或者
# uri: mongodb://zmc:123456@192.168.0.104:27017/zmcdb?authSource=admin
@Autowired
private MongoTemplate mongoTemplate;
/**
* 判断集合(表)是否存在,删除集合(表),创建集合(表)
*/
@Test
public void createCollections() {
final String COLLECTION_NAME = "student_info";
boolean exists = mongoTemplate.collectionExists(COLLECTION_NAME);
if (exists) {
mongoTemplate.dropCollection(COLLECTION_NAME);
}
mongoTemplate.createCollection(COLLECTION_NAME);
}
@Document
@MongoId
@Field
@Transient
@Document("student_info")
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class StudentInfoDTO {
@MongoId
private Integer id;
@Field("stuName")//自定义文档的字段名
private String name;
@Field
private Integer age;
@Field
private Character sex;
@Field
private Date birthday;
}
id不能重复,如果重复就会抛出异常
@Test
public void insertSingle() {
StudentInfoDTO dto=new StudentInfoDTO(1,"张三",23,'男',new Date());
StudentInfoDTO insert = mongoTemplate.insert(dto);
}
相同id再次新增就会报错
@Test
public void insertMore() {
List<StudentInfoDTO> listDto=new ArrayList<>(3);
StudentInfoDTO dto1=new StudentInfoDTO(2,"小明",2,'男',new Date());
StudentInfoDTO dto2=new StudentInfoDTO(3,"小黑",21,'女',new Date());
StudentInfoDTO dto3=new StudentInfoDTO(4,"小白",20,'男',new Date());
listDto.add(dto1);
listDto.add(dto2);
listDto.add(dto3);
Collection<StudentInfoDTO> insert = mongoTemplate.insert(listDto, StudentInfoDTO.class);
}
若id存在,则修改该文档
@Test
public void saveSingle() {
StudentInfoDTO dto=new StudentInfoDTO(1,"老六",213,'男',new Date());
StudentInfoDTO save = mongoTemplate.save(dto);
}
Criteria是标准查询的接口,可以引用静态的Criteria.where的把多个条件组合在起,就可以轻松地将多个方法标准和查询连接起来,方便我们操作查询语句。
Criteria | MongoDB | SQL |
---|---|---|
Criteria and (String key) | $and | where field1=1 and field2=2 |
Criteria andOperator(Criteria… criteria) | $and | where field1=1 and field2=2 |
Criteria orOperator (Criteria. … criteria) | $or | where field1=1 or field2=2 |
Criteria gt (Object o) | $gt | where field>1 |
Criteria gte (Object o) | $gte | where field>=1 |
Criteria in (Object… o) | $in | where field in (1,2,3) |
Criteria is (Object o) | $is | where field =1 |
Criteria It(Object o) | $lt | where field<1 |
Criteria Ite (Object o) | $lte | where field<=1 |
Criteria nin (Object… o) | $nin | where field not in (1,2,3) |
@Test
public void criteriaFind() {
//查询age>20 and stuName in ('老六','小黑')
Query query = new Query(Criteria.where("age").gt(20).and("stuName").in("老六", "小黑"));
List<StudentInfoDTO> dtoList = mongoTemplate.find(query, StudentInfoDTO.class);
dtoList.forEach(System.out::println);
}
@Test
public void findById() {
StudentInfoDTO byId = mongoTemplate.findById(1, StudentInfoDTO.class);
System.out.println(byId);
}
@Test
public void findOne() {
StudentInfoDTO one = mongoTemplate.findOne(new Query(), StudentInfoDTO.class);
System.out.println(one);
}
> and in
@Test
public void criteriaFind() {
//查询age>20
Query query = new Query(Criteria.where("age").gt(20));
List<StudentInfoDTO> dtoList = mongoTemplate.find(query, StudentInfoDTO.class);
dtoList.forEach(System.out::println);
}
> or and =
@Test
public void criteriaFind2() {
//查询age>30 or stuName = '小白' and sex='男'
Criteria criteria = new Criteria().orOperator(
Criteria.where("age").gt(30),
Criteria.where("stuName").is("小白")
).andOperator(
Criteria.where("sex").is("男")
);
Query query = new Query(criteria);
List<StudentInfoDTO> studentInfoDTOS = mongoTemplate.find(query, StudentInfoDTO.class);
studentInfoDTOS.forEach(System.out::println);
}
like
@Test
public void criteriaFind3() {
//查询stuName like '%小%'
Criteria criteria = Criteria.where("stuName").regex("小");
Query query = new Query(criteria);
List<StudentInfoDTO> studentInfoDTOS = mongoTemplate.find(query, StudentInfoDTO.class);
studentInfoDTOS.forEach(System.out::println);
}
order by 排序
@Test
public void criteriaFind4() {
//查询sex='男' order by age desc
Criteria criteria = new Criteria();
criteria.andOperator(Criteria.where("sex").is("男"));
Query query = new Query(criteria);
query.with(Sort.by(Sort.Order.desc("age")));
List<StudentInfoDTO> studentInfoDTOS = mongoTemplate.find(query, StudentInfoDTO.class);
studentInfoDTOS.forEach(System.out::println);
}
skip limit分页
@Test
public void criteriaFind5() {
//where birthday<=当前时间 limit 1,3
Criteria criteria = new Criteria();
criteria.andOperator(Criteria.where("birthday").lte(new Date()));
Query query = new Query(criteria);
query.skip(1).limit(3);
List<StudentInfoDTO> studentInfoDTOS = mongoTemplate.find(query, StudentInfoDTO.class);
studentInfoDTOS.forEach(System.out::println);
}
@Test
public void criteriaFindOne() {
//查询age>20 and stuName not in ('老六')
Query query = new Query(Criteria.where("age").gte(20).and("stuName").nin("老六"));
StudentInfoDTO one = mongoTemplate.findOne(query, StudentInfoDTO.class);
System.out.println(one);
}
json查询不能分页和排序
@Test
public void criteriaFind6() {
//where age>=20 and stuName like '%小%'
String json = "{age:{$gte:20},stuName:{$regex:\"小\"}})";
Query query = new BasicQuery(json);
query.with(Sort.by(Sort.Order.asc("age")));
List<StudentInfoDTO> studentInfoDTOS = mongoTemplate.find(query, StudentInfoDTO.class);
studentInfoDTOS.forEach(System.out::println);
}
更新前的数据
更新后的数据
@Test
public void updateFirst() {
//update table set age+10 where age > 100 or stuName in ('小明','大明')
Criteria criteria = new Criteria();
criteria.orOperator(Criteria.where("age").gt(100),Criteria.where("stuName").in("小明", "大明"));
Query query = new Query(criteria);
Update update = new Update();
update.inc("age",10);
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, StudentInfoDTO.class);
System.out.println(updateResult);
}
更新前的数据
更新后的数据
@Test
public void updateMulti() {
//update table set age=18 where sex='女'
Query query = new Query(Criteria.where("sex").is("女"));
Update update = new Update();
update.set("age", 18);
UpdateResult updateResult = mongoTemplate.updateMulti(query, update, StudentInfoDTO.class);
System.out.println(updateResult);
}
更新前的数据
更新后的数据
@Test
public void upsert(){
//update table set stuName="zmc",age=500,sex='男',salary=999999 where id=666
Query query = new Query(Criteria.where("id").is(666));
Update update = new Update();
update.set("stuName","zmc")
.set("age",500)
.set("salary",999999);
UpdateResult upsert = mongoTemplate.upsert(query, update, StudentInfoDTO.class);
System.out.println(upsert);
}
删除前的数据
删除后的数据
@Test
public void remove() {
//delete from table where salary>100 or stuName='中白'
Criteria criteria = new Criteria();
criteria.orOperator(Criteria.where("salary").gt(100),Criteria.where("stuName").is("中白"));
Query query = new Query(criteria);
DeleteResult remove = mongoTemplate.remove(query, StudentInfoDTO.class);
System.out.println(remove);
}
如统计,求平均值,求和等。
聚合操作分为:单—作用聚合、聚合管道、MapReduce
#统计type=novel或者tag=MongoDB的数量
db.books.count({$or:[{"type" : "novel"},{"tag" : "MongoDB"}]})
该命令会忽略查询条件
db.books.estimatedDocumentCount({$or:[{"type" : "novel"},{"tag" : "MongoDB"}]})
db.books.distinct("type",{$or:[{"type" : "novel"},{"tag" : "MongoDB"}]})
语法
pipeline = [$stage1,$stage2,$stage3...]
db.collection.aggregate(pipeline ,{options})
官方文档
https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/
let tags=["nosql","MongoDB","document","developer","popular"];
let types =["technology","sociality","travel","novel","literature"];
var books=[];
for(let i=0;i<60;i++){
let tagIndx=Math.floor(Math.random()*tags.length);
let tagIndx2=Math.floor(Math.random()*tags.length);
let tyIndx=Math.floor(Math.random()*types.length);
let favCount=Math.floor(Math.random()*120);
let username="zmc"+Math.floor(Math.random()*10);
let age=20+Math.floor(Math.random()*16);
let book={
title:"book_"+(i+1),
type:types[tyIndx],
tag:[tags[tagIndx],tags[tagIndx2]],
favCount:favCount,
author:{name:username,age:age}
};
books.push(book);
}
// console.log(books)
db.books2.insertMany(books);
#载入数据
load("/app/mongodb-linux-x86_64-rhel70-4.4.26/js/books2.js")
查看载入的数据
#pretty是格式化json数据
db.books2.find().pretty()
#把title改为bookName
db.books2.aggregate([{$project:{bookName:"$title"}}])
#把title改为bookName,不展示id,展示type,technology,tag
db.books2.aggregate([{$project:{bookName:"$title",_id:0,type:1,technology:1,tag:1}}])