SQL | MongoDB | 备注 |
---|---|---|
database | database | |
table | collection | |
row | document | |
column | field | |
primary key | primary key | 主键 |
index | index | 索引 |
view | view | 视图 |
前面学习NoSQl的时候已经介绍过,作为反范式,MongoDB可以灵活保存数据
文档校验:处于规范,很多时候我们需要对文档进行约束
required
: 数据可以是任意类型,表示这个数据必须传入max
: 用于Number 类型数据,最大值min
: 用于Number 类型数据,最小值enum
:枚举类型(数组中的类型是String),要求数据必须满足枚举值enum: [‘0’, ‘1’, ‘2’]match
:增加的数据必须符合match(正则)的规则maxlength
:数据必须是String类型,数据最大长度minlength
:数据必须是String类型,数据最小长度bsonType
:数据类型validator: { #校验器
$jsonSchema: { #json数据格式约束
bsonType: "object", #类型
required: [ "name", "year", "major", "address" ], #必须的字段
properties: { #字段规则
name: {
bsonType: "string",
description: "must be a string and is required"
},
year: {
bsonType: "int",
minimum: 2017,
maximum: 3017,
description: "must be an integer in [ 2017, 3017 ] and is required"
},
major: {
enum: [ "Math", "English", "Computer Science", "History", null ],
description: "can only be one of the enum values and is required"
},
gpa: {
bsonType: [ "double" ],
description: "must be a double if the field exists"
},
address: {
bsonType: "object",
required: [ "city" ],
properties: {
street: {
bsonType: "string",
description: "must be a string if the field exists"
},
city: {
bsonType: "string",
"description": "must be a string and is required"
}
}
}
}
}
}
MongoDB通过BSON格式保存文档数据,BSON由一个到多个key-value键值对组成;
文档就像关系数据库的具体数据一样,操作是通过collection进行;
文档操作类似关系数据库,主要分为
命令:
增删改:
db.<collectionName>.<操作>()
查
db.<collectionName>
.find(
{query},#where子句
{fields}#select子句(一般指定查询的field字段)
)
.group()#group子句
.sort()#order by子句
.limit().skip()#limit子句
insertOne
insertMany
insert
# db..insert({data},{options})
db.test1.insert({
"name":"www",
"hhh":123
})
#db..insertMany([{data}……],{options})
db.test.insertMany(
[
{"name":"lili","age":19},
{"name":"liyi","age":20},
{"name":"liuliu","age":21}
]
)
有delete和remove俩种删除方法(推荐使用delete)
# db..remove(,{options})
db.test1.remove({
{"tid":"test"},#query,相当于SQL的where
{"justOne":true}#只删除一条记录
})
db.test1.insert(
{ item: "envelopes", qty : 100, type: "Clasp" },
{ writeConcern: { w: "majority" , wtimeout: 5000 } } #开启写关注
)
改主要有两种手段:覆盖(save、replace)、查询修改(update)
主要操作
#覆盖,save覆盖一般需要携带_id,来覆盖指定id的文档
# db..save(data,{options})
db.test1.save("_id":ObjectId("xxxxxxxxxx"),其他数据部分,{options})
#更新
# db..update(,,{options})
#update:$set、$inc等
db.test1.update({},{$set:{'title':'HHHH'},{options}})
支持组合操作、支持批量操作
# db..find(,)
db.test1.find({}) #查询所有
#查询名字为lili的age字段 SELECT age FROM test1 WHERE name = 'lili'
db.test1.find({"name":"lili"},{"age":1})
db.test.find({$or: [{"age": {$gt:22}},{name:"www"}]})
即SQL的where子句,
数值运算
“key”:{<运算符>:数值}
#score大于等于50分
{
'score':{$gte:50}
}
# 等于
{
'score':50
}
IN
$in
{
'status': { $in: [ "A", "D" ] }
}
条件运算
或:$or
#score大于90或者num小于80
{
$or : [
{'score':{$gt:90}},
{'num':{$lt:80}}
]
}
#与操作
#score大于90并且num小于80
{
'score':{$gt:90},
'num':{$lt:80}
}
模糊查询和正则表达式
MongoDB支持正则表达式操作符$regex来做字符串模式匹配。
{
'title': /^震惊/ #以震惊开头
}
主要有:
-1表示倒排,1表示顺序
)#
db.<collectionName>.aggregate({stage},……)
#下面是管道的两步操作
db.test1.aggregate([
{
$match: { status: "A" }
}, #stage1
{
$group: {
_id: "$cust_id",
total: { $sum: "$amount" }
}
}#stage2
])
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-mongodbartifactId>
dependency>
mongodb:
host: localhost
port: 27017
database: 数据库名
username: XXX
password: xxx
authentication-database: 认证的权限
@Document
:标记实体类@MongoId
:标记主键@Field
:标记为属性(如果属性名和数据库不同需要指定)@Transient
:标记属性不作为数据库的属性@DBRef
:标记属性位一个document对象@Indexed
:标记为该key设置索引@CompoundIndex
:联合索引@CompoundIndexes
:多个联合索引例子
https://www.cnblogs.com/luoxiao1104/p/15145686.html
//实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@CompoundIndexes(
{
@CompoundIndex(def = "{name:1,clazz:1,age:-1}")//联合索引
}
)
@Document("test")
public class StudentEntity {
@MongoId
//@Indexed(unique = true,name = "_id"):默认主键就是唯一索引
private Long id;
private String name;
@Field("class")
@Indexed(name = "class_text")//普通索引
private String clazz;
private Integer age;
private String[] hobby;
private Date dateTime;
@Transient
private String other;
}
//使用
public void updateUser(){
//根据id查询数据
User user = mongoTemplate.findById("611a1cf8d5ba747098ff4625", User.class);
//设置修改的值
user.setName("lisi");
user.setAge(18);
//调用方法实现修改操作
Query query = new Query(Criteria.where("_id").is(user.getId()));
Update update = new Update();
update.set("name",user.getName());
update.set("age",user.getAge());
UpdateResult upsert = mongoTemplate.upsert(query, update, User.class);
long count = upsert.getModifiedCount();
System.out.println(count);
}
可选配置(主要涉及事务和分布式:事务处理机制、读写关注、ack机制、读依赖、写检查)
使用
增:insert和save
改
修改:可以只改一个或者修改多个(First\Multi);可以是update(modify)或者replace
//以只更新一个为例子
//Query:查询更新的文档;BasicUpdate:更新的内容;document更新的文档(key-value形式)
//Class:更新文档参考字段名(即key的字段名),不指定则参考集合的字段名;
//String:集合名
studydb.updateFirst(new Query(), new BasicUpdate(document),StudentEntity.class,"test");
studydb.findAndModify(new Query(), new Update(),
new FindAndModifyOptions(), StudentEntity.class,"test");
//覆盖
studydb.findAndReplace(new Query(), new StudentEntity(),
new FindAndReplaceOptions(),StudentEntity.class,"test");
删
查
聚合函数
管道操作
用于创建查询的中心类。它遵循流畅的API风格,因此您可以轻松地将多个条件链接在一起。标准的静态导入。这种方法提高了可读性。
简单来说就是专门处理条件的类,一般通过静态方法直接创建;
包含前面提到的几乎所有查询:例如
//爱好必须为"睡觉", "吃饭",且顺序一致;
//Criteria.where("hobby").all("睡觉", "吃饭").size(2);爱好是吃饭睡觉,顺序不要求
final Criteria hobby = Criteria.where("hobby").is(new String[]{"睡觉", "吃饭"});
final Criteria criteria = new Criteria();//用于组合条件
final Criteria age = new Criteria("age").lt(22).gt(5);//年龄6-21
final List<StudentEntity> studentEntities = mongoTemplate.find(
new Query(criteria.andOperator(age,new Criteria().orOperator
(hobby,Criteria.where("name").is("zhangsan3")))), StudentEntity.class, "test4");
文本搜索显然是MongoDB的亮点之一,
进行文本搜索,首先需要在文本搜索的Field建立索引
和ES类似,MongoDB的文本搜索也是一个赋分的制度,分值越高说明匹配度越高;
$$text、$search、score、$meta$:是核心关键字
#简单的搜索
db.<collectionName>.find({$text:{$search:"Jon"}})
#多关键词搜索,注意这种搜索是 or的关系,有index 或者 有 operator都可以,所以,这个搜索会出来 Jon Snow,Jon Bon Jovi, Don Jon 等好多名字,而且 Jon Snow还不一定能出现在第一个
db.<collectionName>.find({$text:{$search:"Jon Snow"}})
#有Jon 但是没有Don的
db.<collectionName>.find({$text:{$search:"Jon -Don"}})
#搜索包含Jon Snow的词组。用这个搜索,我发现就出不来了。 因为我们的库里面的词组是Jon Aegon Snow
db.<collectionName>.find({$text:{$search:"\"Jon Snow\""}})
#加了下评分权重的排序。
db.<collectionName>.find( {$text:{$search:"Jon Snow"}}, {score:{$meta:"textScore"}} ).sort({score:{$meta:"textScore"}})
#使用两个短语,这就是一个逻辑上的AND关系,完美。假如你要使用mongodb 多个字符串匹配的查询,就用这个。不过,据说对中文分词不行。
db.<collectionName>.find({$text:{$search:"\"Jon\"\"Snow\""}})
和关系数据库一样,MongoDB的视图也是为了方便对查找进行权限控制
MongoDB的视图支持:查找、统计、管道操作
#视图创建
db.createCollection()
db.createView()
#查找
db.collection.find()
db.collection.findOne()
#聚合操作
db.collection.aggregate()
#统计操作
db.collection.countDocuments()
db.collection.estimatedDocumentCount()
db.collection.count()
#去重
db.collectionName.distinct()
#删除视图
db.collectionName.drop()
{ : { : , … } }
# fruits和aminal都是数组
db.test2.insertMany(
[
{"name":"lili","age":19,"fruits":["apple","banana"],"aminal":["cat","dog"]},
……
]
)
# { : { : , ... } }
db.test2.find( { fruits: ["apple", "banana"], aminal: { $all: ["cat", "dog"] } )
# fruits只包含两个元素"apple","banana"并且按顺序的数组
# $all:表示只要包含"cat"和"dog",不需要知道是否包含其他和顺序
#可以通过下标指定元素(下标由0开始);
db.test2.find( { fruits.1: "apple"} )
#指定fruits第二个元素必须为apple
# $elemMatch:对元素进行多条件查询
#数组中最少一个元素同时满足所有的查询条件。
db.test2.find( { age: { $elemMatch: { $gt: 22, $lt: 30 } } } )
#数组存在一个元素大于22且小于30
# $size:元素的个数
db.test2.find( { fruits: { $size: 3 } } )
#fruits有三个元素的文档
db.test2.insertMany(
[
{"name":"liyi","age":20,"likes":{{"fruits":["watermalon","banana"]},{"aminal":["panda","mouse"]}}},
……
]
)
#由于等值查询,必须对查询的fruits、aminal和likes保存的顺序一致
db.inventory.find( { likes: { fruits: [], aminal:[] } } )
#指定likes的fruilts的第二个元素
db.test2.find( { likes.fruits.1: "apple"} )
支持运算符
$match:滤波操作(相当于where)
$project:投影操作(相当于SELECT xxx)
$group: 相当于group by
$sort: 相当于order by
$limit和$skip: 相当于limit
$lookup: 左连接
$graphLookup:图连接
{
$lookup: {
from: "xxx", #连接的外部表
localField: "xx", #外部表和本表连接的键
foreignField: "xx", #外键
as: ""#连接的外部表的属性的别名
}
}
{
$graphLookup: {
from: <collection>,
startWith: <expression>,
connectFromField: <string>,
connectToField: <string>,
as: <string>,
maxDepth: <number>,
depthField: <string>,
restrictSearchWithMatch: <document>
}
}
$unwind:拆分数组
//原数据
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "鲁迅",
"books" : [
{
"name" : "呐喊",
"publisher" : "花城出版社"
},
{
"name" : "彷徨",
"publisher" : "南海出版出"
}
]
}
//拆分 db.xxxxx.aggregate({$unwind:"$books"})
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "鲁迅",
"books" : {
"name" : "呐喊",
"publisher" : "花城出版社"
}
}
{
"_id" : ObjectId("59f93c8b8523cfae4cf4ba86"),
"name" : "鲁迅",
"books" : {
"name" : "彷徨",
"publisher" : "南海出版出"
}
}
db..aggregate([{管道操作}])
视图不支持文本搜索。
前面已经介绍过使用(在有文本所有的field中)
聚合框架下的文本查询的限制
$text的$search必须在聚合的第一个Stage
只能有一次$search
如果需要按照分数排序需要在后面的Stage中进行(默认不会排序)
db.test.aggregate(
[
{ $match: { $text: { $search: "cake tea" } } }, #第一阶段进行search
{ $project: { title: 1, _id: 0, score: { $meta: "textScore" } } },#需要排序,必须自己排序
{ $match: { score: { $gt: 1.0 } } }
]
)