BSON=二进制的JSON
windows版本的直接去官网下载即可,这里的安装运行我试了一次没有成功。干脆不用了,反正以后也不会在windows系统上用的这个
这里使用docker容器的方式安装使用。
直接docker拉取镜像运行
docker pull mongo
新建数据持久化目录
mkdir -p /docker_volume/mongodb/data
创建并运行容器
docker run -itd --name mongo -v /docker_volume/mongodb/data:/data/db -p 27017:27017 mongo:latest
进入mongodb的admin数据库
docker exec -it mongo mongo admin
这条好像是高版本用的
docker exec -it mongo mongosh admin
创建用户
新版本的默认有一个root用户。
db.createUser({ user:'root',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'},'readWriteAnyDatabase']});
设置密码
db.auth('root', '123456')
在可视化界面直接连接即可.
不存在的数据库会直接在内存里创建,但是没有在磁盘创建。
use DATABASE_NAME
show dbs
show databases
MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。
注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
删除当前数据库
db.dropDatabase()
使用db可以查看当前所在数据库
在某一个数据库下通过指定集合名字的方式删除
db.collectionName.drop()
db.createCollection(name, options)
参数说明:
options 可以是如下参数:
字段 | 类型 | 描述 |
---|---|---|
capped | 布尔 | (可选)如果为 true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。 当该值为 true 时,必须指定 size 参数。 |
autoIndexId | 布尔 | 3.2 之后不再支持该参数。(可选)如为 true,自动在 _id 字段创建索引。默认为 false。 |
size | 数值 | (可选)为固定集合指定一个最大值,即字节数。 如果 capped 为 true,也需要指定该字段。 |
max | 数值 | (可选)指定固定集合中包含文档的最大数量。 |
在插入文档时,MongoDB 首先检查固定集合的 size 字段,然后检查 max 字段。
show tables
show collections
其中
db.COLLECTION_NAME.insert(document)
或
db.COLLECTION_NAME.save(document)
3.2 版本之后新增了 db.collection.insertOne() 和 db.collection.insertMany()。
db.collection.insertOne() 用于向集合插入一个新文档,语法格式如下:
db.collection.insertOne(
,
{
writeConcern:
}
)
db.collection.insertMany() 用于向集合插入一个多个文档,语法格式如下:
db.collection.insertMany(
[ , , ... ],
{
writeConcern: ,
ordered:
}
)
参数说明:
db.collection.update(
,
,
{
upsert: ,
multi: ,
writeConcern:
}
)
参数说明:
修改也分为两种
一个是覆盖修改
db.my.update({"_id":"1"},{name:"yhy3"})
覆盖修改会导致只剩下修改字段,最新版本里面好像移除了这个覆盖修改,会报错
MongoInvalidArgumentError: Update document requires atomic operators
一个是局部的修改
db.my.update({"_id":"1"},{$set:{name:"yhy3"}})
批量修改
以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true。
db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})
删除 status 等于 D 的一个文档:
会优先删除插入时间早的文档.
db.inventory.deleteOne( { status: "D" } )
删除 status 等于 A 的全部文档:
db.inventory.deleteMany({ status : "A" })
如删除集合下全部文档:
db.inventory.deleteMany({})
db.collection.find(query, projection)
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.col.find().pretty()
除了 find() 方法之外,还有一个 findOne() 方法,它只返回一个文档。
MongoDB和SQL的条件语句比较
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | { } |
db.col.find({"by":"菜鸟教程"}).pretty() |
where by = '菜鸟教程' |
小于 | { |
db.col.find({"likes":{$lt:50}}).pretty() |
where likes < 50 |
小于或等于 | { |
db.col.find({"likes":{$lte:50}}).pretty() |
where likes <= 50 |
大于 | { |
db.col.find({"likes":{$gt:50}}).pretty() |
where likes > 50 |
大于或等于 | { |
db.col.find({"likes":{$gte:50}}).pretty() |
where likes >= 50 |
不等于 | { |
db.col.find({"likes":{$ne:50}}).pretty() |
where likes != 50 |
and条件
db.col.find({key1:value1, key2:value2}).pretty()
or条件
db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
db.COLLECTION_NAME.aggregate(AGGREGATE_OPERATION)
表达式 | 描述 | 实例 |
---|---|---|
$sum | 计算总和。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$sum : "$likes"}}}]) |
$avg | 计算平均值 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$avg : "$likes"}}}]) |
$min | 获取集合中所有文档对应值得最小值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$min : "$likes"}}}]) |
$max | 获取集合中所有文档对应值得最大值。 | db.mycol.aggregate([{$group : {_id : "$by_user", num_tutorial : {$max : "$likes"}}}]) |
$push | 将值加入一个数组中,不会判断是否有重复的值。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$push: "$url"}}}]) |
$addToSet | 将值加入一个数组中,会判断是否有重复的值,若相同的值在数组中已经存在了,则不加入。 | db.mycol.aggregate([{$group : {_id : "$by_user", url : {$addToSet : "$url"}}}]) |
$first | 根据资源文档的排序获取第一个文档数据。 | db.mycol.aggregate([{$group : {_id : "$by_user", first_url : {$first : "$url"}}}]) |
$last | 根据资源文档的排序获取最后一个文档数据 | db.mycol.aggregate([{$group : {_id : "$by_user", last_url : {$last : "$url"}}}]) |
skip用于跳过前面的页数,limit用于指定页面大小,差不多就是这个用法。
正则的复杂条件查询,比较查询,包含查询,条件连接查询, 等的用到再去查吧。
索引
索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
db.collection.createIndex(keys, options)
语法中 Key 值为你要创建的索引字段,1 为指定按升序创建索引,如果你想按降序来创建索引指定为 -1 即可。
db.col.createIndex({"title":1})
createIndex() 方法中你也可以设置使用多个字段创建索引(关系型数据库中称作复合索引)。
db.col.createIndex({"title":1,"description":-1})
createIndex() 接收可选参数,可选参数列表如下:
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false。 |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false. |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。 |
dropDups | Boolean | 3.0+版本已废弃。在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false. |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false. |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language. |
在后台创建索引:
db.values.createIndex({open: 1, close: 1}, {background: true})
db.col.getIndexes()
db.col.totalIndexSize()
db.col.dropIndexes()
db.col.dropIndex("索引名称")
你可以使用explain
方法来查看MongoDB执行查询的计划,以确保它使用了正确的索引。例如:
db.yourCollection.find({ field_name: "your_value" }).explain("")
使用索引进行查询可以看见下面的IXSCAN,表示的是索引扫描
新建一个maven模块,导入mongodb的依赖
org.springframework.boot
spring-boot-starter-data-mongodb
编写配置文件
spring:
data:
mongodb:
host: 127.0.0.1
database: articledb
port: 27017
#也可以通过uri的方式配置
#uri: mongodb://127.0.0.1:27017/admin?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.1.0
/**
* 文章评论实体类
*/
//把一个java类声明为mongodb的文档,可以通过collection参数指定这个类对应的文档。
//@Document(collection="mongodb 对应 collection 名")
// 若未加 @Document ,该 bean save 到 mongo 的 comment collection
// 若添加 @Document ,则 save 到 comment collection
@Document(collection="comment")//可以省略,如果省略,则默认使用类名小写映射集合
//复合索引
@CompoundIndex( def = "{'userid': 1, 'nickname': -1}")
public class Comment implements Serializable {
//主键标识,该属性的值会自动对应mongodb的主键字段"_id",如果该属性名就叫“id”,则该注解可以省略,否则必须写
// @Id
private String id;//主键
//该属性对应mongodb的字段的名字,如果一致,则无需该注解
@Field("content")
private String content;//吐槽内容
private Date publishtime;//发布日期
//添加了一个单字段的索引
@Indexed
private String userid;//发布人ID
private String nickname;//昵称
private LocalDateTime createdatetime;//评论的日期时间
private Integer likenum;//点赞数
private Integer replynum;//回复数
private String state;//状态
private String parentid;//上级ID
private String articleid;
//getter and setter.....
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getPublishtime() {
return publishtime;
}
public void setPublishtime(Date publishtime) {
this.publishtime = publishtime;
}
public String getUserid() {
return userid;
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public LocalDateTime getCreatedatetime() {
return createdatetime;
}
public void setCreatedatetime(LocalDateTime createdatetime) {
this.createdatetime = createdatetime;
}
public Integer getLikenum() {
return likenum;
}
public void setLikenum(Integer likenum) {
this.likenum = likenum;
}
public Integer getReplynum() {
return replynum;
}
public void setReplynum(Integer replynum) {
this.replynum = replynum;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getParentid() {
return parentid;
}
public void setParentid(String parentid) {
this.parentid = parentid;
}
public String getArticleid() {
return articleid;
}
public void setArticleid(String articleid) {
this.articleid = articleid;
}
@Override
public String toString() {
return "Comment{" +
"id='" + id + '\'' +
", content='" + content + '\'' +
", publishtime=" + publishtime +
", userid='" + userid + '\'' +
", nickname='" + nickname + '\'' +
", createdatetime=" + createdatetime +
", likenum=" + likenum +
", replynum=" + replynum +
", state='" + state + '\'' +
", parentid='" + parentid + '\'' +
", articleid='" + articleid + '\'' +
'}';
}
}
public interface CommentRepository extends MongoRepository {
}
@Service
public class CommentService {
@Resource
private CommentRepository commentRepository;
@Autowired
private MongoTemplate mongoTemplate;
/**
* 保存一个评论
* @param comment
*/
public void saveComment(Comment comment){
//如果需要自定义主键,可以在这里指定主键;如果不指定主键,MongoDB会自动生成主键
//设置一些默认初始值。。。
//调用dao
commentRepository.save(comment);
}
/**
* 更新评论
* @param comment
*/
public void updateComment(Comment comment){
//调用dao
commentRepository.save(comment);
}
/**
* 根据id删除评论
* @param id
*/
public void deleteCommentById(String id){
//调用dao
commentRepository.deleteById(id);
}
/**
* 查询所有评论
* @return
*/
public List findCommentList(){
//调用dao
return commentRepository.findAll();
}
/**
* 根据id查询评论
* @param id
* @return
*/
public Comment findCommentById(String id){
//调用dao
return commentRepository.findById(id).get();
}
}
@SpringBootTest
class ArticleApplicationTests {
@Autowired
private CommentService commentService;
@Test
void testSave() {
Comment comment = new Comment();
comment.setContent("这是一条评论");
comment.setPublishtime(new Date());
comment.setUserid("user123");
comment.setNickname("John Doe");
comment.setCreatedatetime(LocalDateTime.now());
comment.setLikenum(0);
comment.setReplynum(0);
comment.setState("active");
comment.setParentid(null);
comment.setArticleid("article123");
commentService.saveComment(comment);
}
@Test
void testselectList(){
System.out.println(commentService.findCommentList());// 返回一个数组
System.out.println(commentService.findCommentById("65740c95da8e264ac2db678f"));//返回一个对象
}
@Test
void testUpdate(){
Comment comment = commentService.findCommentById("65740c95da8e264ac2db678f");
System.out.println("原本的点赞数:"+comment.getLikenum());
comment.setLikenum(comment.getLikenum()+1); //将点赞数+1
commentService.updateComment(comment);
comment=commentService.findCommentById("65740c95da8e264ac2db678f");
System.out.println("新的点赞数:"+comment.getLikenum());
}
@Test
void testDelete(){
commentService.deleteCommentById("65740c95da8e264ac2db678f");
}
}
dao层新建接口方法
这里方法名一定要是这个findByParentid,否则会报错
package com.yhy.article.dao;
import com.yhy.article.pojo.Comment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface CommentRepository extends MongoRepository {
Page findByParentid(String parentid,Pageable pageable);
}
服务层调用
public Page findCommentListByParentid(String parentid, int page, int size) {
return commentRepository.findByParentid(parentid, PageRequest.of(page-1,size));
}
测试类编写
@Test
void testFindCommentListByParentId(){
Page page = commentService.findCommentListByParentid("3", 1, 2);
System.out.println(
page.getTotalElements()
);
System.out.println(page.getContent());
}
简单代码
正确代码
public void updateCommentLikenum(String id){
// 查询条件
Query query = Query.query(Criteria.where("_id").is(id));
// 更新条件
Update update = new Update();
update.inc("likenum");
//也可以设置更多的更新
//update.set("content","这是新的评论.");
//参数1.查询条件
//参数2.更新条件
//参数3.集合的名字或者实体类的类型Comment.class
mongoTemplate.updateFirst(query,update,Comment.class);
}