SpringBoot 版本 2.3.4.RELEASE
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
application.properties
spring.data.mongodb.uri=mongodb://iotroot:iotpwd@192.168.9.100:27017/ttsf_business_iot
# iotroot 用户名
# iotpwd 密码
# business_iot 数据库
Entity
import lombok.Data;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.Date;
import java.util.List;
@Data
@Document(collection = "lsp_config_log")
public class LspConfigLog {
@Id
private ObjectId id;
private int age;
private int shengao;
private int tizhong;
private String name;
private String alias;
private Date createTime;
private List<Man> lspList;
@Data
public static class Man{
private String name;
private int age;
public Man(String name, int age) {
this.name = name;
this.age = age;
}
}
}
注解释义
@Id
主键,不可重复,自带索引,可以在定义的列名上标注,需要自己生成并维护不重复的约束。如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。原因可参考上一篇mongo和mysql的性能对比。
在实际业务中不建议自己设置主键,应交给mongo自己生成,自己可以设置一个业务id,如int型字段,用自己设置的业务id来维护相关联的表。
@Indexed
声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。
唯一索引的话是@Indexed(unique = true)。
也可以对数组进行索引,如果被索引的列是数组时,MongoDB会索引这个数组中的每一个元素。
也可以对整个Document进行索引,排序是预定义的按插入BSON数据的先后升序排列。
也可以对关联的对象的字段进行索引,譬如User对关联的address.city进行索引。
@Transient
被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。
API
查询
import com.alibaba.fastjson.JSONObject;
import com.bjttsf.iot.mongo.LspConfigLog;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Sort;
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.data.mongodb.core.schema.JsonSchemaObject.Type;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class mongoTest {
@Resource
private MongoTemplate mongoTemplate;
/*
(>) 大于 - $gt
(<) 小于 - $lt
(>=) 大于等于 - $gte
(<= ) 小于等于 - $lte
*/
@org.junit.Test
public void querlspByType() {
Criteria criteria = Criteria
.where("age").lt(36)
.where("name").type(Type.STRING) // 列的数据类型是String 的
.where("name").is("lisi")// 全匹配
// .where("name").regex( "lisi" )// 前后模糊查詢,
// .where("name").not().regex("lisi" )// 不包含
// .where("name").regex( "^lisi" )// 以lisi 开头的
.where("name").regex( "lisi$" )// 以lisi 结尾的
;
// 多排序条件
List<Sort.Order> orders = new LinkedList<>();
Sort.Order or = new Sort.Order(Sort.Direction.DESC, "createTime");
orders.add(or);
Query query = new Query(criteria).with(Sort.by(orders));
// 单排序条件
new Query().with(Sort.by(Sort.Direction.DESC,"createTime"))
// 分页
int pageNum = null == vo.getPageNum()?1:vo.getPageNum();
int pageSize = null == vo.getPageSize()?10:vo.getPageSize();
// PageRequest pages = PageRequest.of((pageNum - 1) , pageSize);
PageRequest pages = PageRequest.of((pageNum - 1) , pageSize, Sort.by(Sort.Direction.DESC, "t"));
// 查询
// mongoTemplate.find(query, RelayData.class);
mongoTemplate.find(query.with(pages), RelayData.class);
}
}
保存、修改、删除
@org.junit.Test
public void config() {
LspConfigLog config =new LspConfigLog();
/*-----------------------------------------------*/
// 如果 _id 主键存在则更新数据,如果不存在就插入数据
mongoTemplate.save(config);
/*-----------------------------------------------*/
// 若插入的数据主键已经存在 则会抛 org.springframework.dao.DuplicateKeyException 异常提示主键重复
mongoTemplate.insert(config);
/*-----------------------------------------------*/
Query query = new Query(criteria).with(Sort.by("createTime"));
Update up = new Update();
up.set("age",88);
// 查詢到的進行修改,全部
mongoTemplate.updateMulti(query,up,LspConfigLog.class);
/*-----------------------------------------------*/
Query query = new Query(criteria).with(Sort.by("createTime"));
Update up = new Update();
up.set("age",88);
// 查詢到的進行修改,第一个
mongoTemplate.updateFirst(query,up,LspConfigLog.class);
/*-----------------------------------------------*/
Query query = new Query(criteria).with(Sort.by("createTime"));
Update up = new Update();
up.set("age",88);
// 查询到就进行修改,查询不到进行插入
mongoTemplate.upsert(query,up,LspConfigLog.class);
/*-----------------------------------------------*/
DeleteResult remove = mongoTemplate.remove(query, LspConfigLog.class);
// 刪除
System.out.println(JSONObject.toJSONString(remove.getDeletedCount()));
}
sql 操作
查询
db.lsp_config_log.find({"age":{$lt:50}}).pretty();
插入
db.lsp_config_log.insert({"age":99,"shengao":175,"tizhong":189,"add":"上海"});
修改
//upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
//multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
db.lsp_config_log.update({"age":{$gt:99}},{$set:{"addr":"洛阳"}},{upsert :true,multi :true});
删除
db.lsp_config_log.remove({"age":{$lt:20}});
索引操作
查询所有索引
db.lsp_config_log.getIndexes()
resurt:
[
{
v: NumberInt("2"),
key: {
_id: NumberInt("1")
},
name: "_id_"
}
]
创建索引
db.lsp_config_log.createIndex({companyId:1,relayId:1}) //联合索引
db.lsp_config_log.createIndex({createTime:-1})
1:正序;-1:倒叙;
resurt:
[
{
v: NumberInt("2"),
key: {
_id: NumberInt("1")
},
name: "_id_"
},
{
v: NumberInt("2"),
key: {
createTime: 1
},
name: "createTime_1"
}
]
删除索引
db.lsp_config_log.dropIndex("createTime_1")
什么时候需要索引
db.lsp_config_log.find({}).sort({})
创建索引的依据:
(1).Find命令中有条件时,根据条件字段创建索引
(2).Sort中有排序字段时,根据排序字段创建索引
索引的考虑的因素:
(1)产品需求决定查询,查询条件决定索引
(2)查询键的方向性,联合索引需要考虑键的方向问题
(3)扩展性
索引的分类
主键索引:_id键索引,系统保证和维护键值的唯一性。不能被删除。主键可以为null
普通索引:分为单键和复合索引。
唯一索引:也叫唯一约束,能保证和维护键值的唯一性。
地理空间索引:查找和定位地理空间
自增主键
建立一个表,表里面给需要自增的表结构维护一个自增值,如下:
建议collName 数据提前给个默认值,否则第一条数据并发的时候会有“惊喜”
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Document(collection = "iot_sequence")
public class SequenceId implements Serializable {
private static final long serialVersionUID = 7523059264202861246L;
@Field
@Indexed
private String collName;// 集合名称
@Field
private long seqId;// 序列值
public String getCollName() {
return collName;
}
public void setCollName(String collName) {
this.collName = collName;
}
public long getSeqId() {
return seqId;
}
public void setSeqId(long seqId) {
this.seqId = seqId;
}
}
/*---------------------SpringBoot + mongodb--------------------------*/
/**
* 返回下一个自增的ID
*
* @param collName
* 集合名称(一般规则是,类名的第一个字母小写,然后按照驼峰书写法)
* @return Long 序列值
*/
private Long getNextId(String collName) {
Query query = new Query(Criteria.where("collName").is(collName));
List<SequenceId> list = mongoTemplate.find(query, SequenceId.class);
SequenceId seq = null;
Date now = new Date();
if(list.size() > 0){
Update update = new Update();
update.inc("seqId", 1);
FindAndModifyOptions options = new FindAndModifyOptions();
options.upsert(true);
options.returnNew(true);
seq = mongoTemplate.findAndModify(query, update, options, SequenceId.class);
return seq.getSeqId();
}else{
seq = new SequenceId();
seq.setCollName(collName);
seq.setGmtCreate(now);
seq.setIsDelete("0");
seq.setSeqId((long) 1);
mongoTemplate.save(seq);
return seq.getSeqId();
}
}
/*---------------------java SE + mongodb--------------------------*/
static MongoClient mongoClient = MongoUtils.getConnect();
static MongoDatabase mongoDatabase = MongoUtils.getDatabase(mongoClient);
public static Long getNextId(String name){
MongoCollection<Document> collection = mongoDatabase.getCollection("ttsf_iot_sequence");
Bson filter = null;
SequenceId sequenceId = new SequenceId();
filter = eq("collName",name);
FindIterable<Document> documents = collection.find(filter);
Document first = documents.first();
if (null != first){
Bson query = null;
query = Updates.inc("seqId",1);
Document oneAndUpdate = collection.findOneAndUpdate(first, query);
return Long.valueOf(oneAndUpdate.getInteger("seqId"));
}else{
sequenceId.setCollName(name);
sequenceId.setSeqId(1);
collection.insertOne(Document.parse(JSONObject.toJSONString(sequenceId)));
return sequenceId.getSeqId();
}
}