Mongodbd的简学

1、MongoDB相关概念

1.1、业务场景

三高:

  • 高并发
  • 高性能
  • 高可用
    High Performance: 对数据库的高并发读写的要求
    High Storage: 对海量数据的高效率存储和访问的需求
    High Scalability && High Available: 对数据的高扩展性和高可用性的需求

应用场景:

  • 社交场景:存储用户信息、朋友圈等信息
  • 游戏场景:存储游戏用户信息, 用户的装备, 积分等直接以内嵌文档的形式存储, 方便查询, 高效率存储和访问.
  • 物流场景:订单状态在运送过程中会不断更新, 以 MongoDB 内嵌数组的形式来存储, 一次查询就能将订单所有的变更读取出来.
  • 物联网场景:存储所有接入的智能设备信息, 以及设备汇报的日志信息, 并对这些信息进行多维度的分析
  • 视频直播:用户信息, 点赞互动信息等

共同特点:
1、数据量大
2、写入操作频繁
3、价值低的数据,对事务性要求不高


什么时候选择Mongodb
1、应用不需要事务与复杂的join支持
2、新应用,需求会变,数据模型无法确定
3、应用要2-3k以上的读写QPS
4、需要TB或者PB级别的数据存储
5、快速发展,需要快速水平扩展
6、要求存储的数据不丢失
7、需要99.99%的高可用
8、大量的地理位置查询,文本查询
符合一个可以考虑mongodb,符合2个就确定mongodb

1.2、Mongodb简介

MongoDB是一个开源,高性能,无模式的文档型数据库, 简化开发和方便扩展, 是NoSQL数据库产品中的一种 是最像关系型数据库(MySQL)的非关系型数据库.
它支持的数据结构非常松散, 是一种类似于 JSON 的 格式叫BSON, 所以它既可以存储比较复杂的数据类型, 又相当的灵活. MongoDB中的记录是一个文档, 它是一个由字段和值对(field:value)组成的数据结构
MongoDB文档类似于JSON对象, 即一个文档认 为就是一个对象.字段的数据类型是字符型, 它的值除了使用基本的一些类型外, 还可以包括其他文档, 普通数组和文档数组.

1.3、结构

在这里插入图片描述
在这里插入图片描述

1.4、数据模型

DB最小的存储单位就是文档(document)对象。
文档对应关系型数据库的行。
在这里插入图片描述
shell默认使用64位浮点型数值。

1.5、特点

高性能:
数据的持久性,对嵌入式数据模型的支持减少了数据库系统上的i/o活动。
索引支持更快查询,可以包含来自嵌入式文档和数组的键。
高可用:
bd的复制工具称为副本集(replica set),可提供自动故障转移和数据冗余。
高扩展性:
提供了水平扩展性作为核心功能的一部分。
分片将数据分布在一组集群。
丰富的查询支持:
支持丰富的查询语言,支持读和写操作,比如数据聚合,文本搜索和地理空间查询等。
其他特点:
无模式、灵活的文档模型。

2、单机部署

2.1、windows系统中安装启动

下载地址
在这里插入图片描述

2.1.1、启动方式1

首先创建一个数据缓存的文件夹,一般创建bin文件夹的同级目录 data
在bin目录里面启动cmd

mongod --dbpath =..\data\db

如果启动报错,那么就是db文件没创建,自己去data文件夹创建db文件夹
默认端口27017

2.1.2、启动方式2

使用配置方式
在bin的同级目录中创建conf
创建文件夹mongod.conf

storage:
	dbPath: D:\Environment\Mongodb\mongodb-win32-x86_64-windows-6.0.0\data

服务启动后,在bin目录下新创一个cmd窗口

3、基本常用命令

将文章评论的数据存入
在这里插入图片描述

3.1、选择和创建数据库

选择和创建数据库的语法格式:

use 数据库

没有则创建、有就是切换到该数据库

查看有权限 ,查看所有的数据库命令

show dbs
或者
show databases

3.2、删除

db.dropDatabase()

主要用来删除已经持久化的数据库

3.3、集合操作

集合的显示创建

db.createCollection("name")

#查看
show name
show table

集合的隐式创建
向一个集合中 直接插入文档,如果不存在文档,那么就会自动创建

3.4、集合的删除

db.collection.drop()
或者
db.集合.drop()

3.5、文档的CRUD

文档的数据结构和JSON基本一样
所有存储在集合中的数据都是Bson格式

3.5.1、插入

1、单个文档插入
使用insert()或者save()

db.collection.insert(
	<document or array of document>,
	{
	writeConcern: <document>,
	ordered: <boolean>
	}
)

在这里插入图片描述
在这里插入图片描述
多个文档插入:

try {
  db.comment.insertMany([
    {"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上, 健康很重要, 一杯温水幸福你我 他.","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-0805T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
    {"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水, 冬天喝温开水","userid":"1005","nickname":"伊人憔 悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
    {"_id":"3","articleid":"100001","content":"我一直喝凉开水, 冬天夏天都喝.","userid":"1004","nickname":"杰克船 长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
    {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭, 影响健康.","userid":"1003","nickname":"凯 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
    {"_id":"5","articleid":"100001","content":"研究表明, 刚烧开的水千万不能喝, 因为烫 嘴.","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-0806T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}

]);

} catch (e) {
  print (e);
}

insertMany()而不是insert()
在这里插入图片描述

3.5.2、查询数据

db.comment.find()
或者指定查询
db.comment.find({userid:'1003'})

投影查询:

db.comment.find({userid:"1003"},{userid:1,nickname:1})

在这里插入图片描述

3.5.3、文档的更新

db.collection.update(query,update,options)
# 或者
db.collection.update(
	<query>,
	<update>,
	{
	upsert:<boolean>,
	multi:<boolean>,
	writeConcern:<document>,
	collation:<document>,
	arrayFilters: [<filterdocument1>,...],
	hint: <document | string>
	}
)

在这里插入图片描述
在这里插入图片描述

3.5.4、每次递增1 $inc

db.comment.update({_id:"3"},{$inc:{likenum:NumberInt(1)}})

3.5.5、删除文档

语法结构:

db.集合名词.remove(条件)

#全删
db.comment.remove({})
#要删除id=1的
db.comment.remove({_id:"1"})

3.6、文档的分页查询

3.6.1、统计查询

db.collection.count(query,options)

比如:

#查询所有:
db.comment.count()
#查询id为3的数据
db.comment.count({userid:"3"})

3.6.2、分页列表查询

可以使用limit()方法来读取指定数量的数据,使用skip()方法来跳过指定数量的数据。

#查询前面两条
db.commment.find().limit(2)

#跳过前面2条,查询3 4条
db.comment.find().limit(2).skip(2)

3.6.3、排序查询

sort()方法对数据进行排序,sort()方法可以通过参数指定排序的字段,并使用1与-1来指定排序的方法,其中1为升序,而-1用于降序

db.collection_name.find().sort({key:1})
或者  
db.集合名称.find().sort(排序方式)

3.7、更多的复杂查询

3.7.1、正则表达式与比较

比如


try {
  db.comment.insertMany([
    {"_id":"1","articleid":"100001","content":"我们不应该把清晨浪费在手机上, 健康很重要, 一杯温水幸福你我 他.","userid":"1002","nickname":"相忘于江湖","createdatetime":new Date("2019-0805T22:08:15.522Z"),"likenum":NumberInt(1000),"state":"1"},
    {"_id":"2","articleid":"100001","content":"我夏天空腹喝凉开水, 冬天喝温开水","userid":"1005","nickname":"伊人憔 悴","createdatetime":new Date("2019-08-05T23:58:51.485Z"),"likenum":NumberInt(888),"state":"1"},
    {"_id":"3","articleid":"100001","content":"我一直喝凉开水, 冬天夏天都喝.","userid":"1004","nickname":"杰克船 长","createdatetime":new Date("2019-08-06T01:05:06.321Z"),"likenum":NumberInt(666),"state":"1"},
    {"_id":"4","articleid":"100001","content":"专家说不能空腹吃饭, 影响健康.","userid":"1003","nickname":"凯 撒","createdatetime":new Date("2019-08-06T08:18:35.288Z"),"likenum":NumberInt(2000),"state":"1"},
    {"_id":"5","articleid":"100001","content":"研究表明, 刚烧开的水千万不能喝, 因为烫 嘴.","userid":"1003","nickname":"凯撒","createdatetime":new Date("2019-0806T11:01:02.521Z"),"likenum":NumberInt(3000),"state":"1"}

]);

} catch (e) {
  print (e);
}

//删除
db.comment.remove({})


db.comment.find()
//正则表达式
db.comment.find({content:/开水/})

-------比较······
//点赞大于700
db.comment.find({likenum:{$gt:NumberInt(700)}})
//其余
//小于   lt   ||    大于等于 gte   || 小于等于 lte  || 不等于 ne

3.7.2、包含查询

$in

//查询userid包含1002 与1003的文档
db.comment.find({userid:{$in:["1002","1003"]}})

3.7.3、条件连接查询

需要查询同时满足两个以上条件,就需要使用$and操作符进行关联(与sql的and相似)
$and:[{},{},{}]
如:查询评论数大于700小于2k

//查询评论集合中likenunm大于700 小于2k的文档
db.comment.find({$and:[{likenum:{$gte:NumberInt(700)}},{likenum:{$lt:NumberInt(2000)}}]})

$or或者
用户id 1003 或者小于2k

db.comment.find({$or:[{userid:"1003"},{likenum:{$lt:NumberInt(2000)}}]})

3.8、常用命令小结

选择切换数据库:use articledb
插入数据:db.comment.insert({bson数据})
查询所有数据:db.comment.find();
条件查询数据:db.comment.find({条件})
查询符合条件的第一条记录:db.comment.findOne({条件})
查询符合条件的前几条记录:db.comment.find({条件}).limit(条数)
查询符合条件的跳过的记录:db.comment.find({条件}).skip(条数)

修改数据:db.comment.update({条件},{修改后的数据})
        或
        db.comment.update({条件},{$set:{要修改部分的字段:数据})

修改数据并自增某字段值:db.comment.update({条件},{$inc:{自增的字段:步进值}})

删除数据:db.comment.remove({条件})
统计查询:db.comment.count({条件})
模糊查询:db.comment.find({字段名:/正则表达式/})
条件比较运算:db.comment.find({字段名:{$gt:值}})
包含查询:db.comment.find({字段名:{$in:[值1, 值2]}})
        或  nin:不包含
        db.comment.find({字段名:{$nin:[值1, 值2]}})

条件连接查询:db.comment.find({$and:[{条件1},{条件2}]})
           或
           db.comment.find({$or:[{条件1},{条件2}]})

4、索引

索引在 MongoDB 中高效地执行查询.如果没有索引, MongoDB 必须执行全集合扫描.这种扫描全集合的查询效率是非常低的, 特别在处理大量的数据时, 查询可以要花费几十秒甚至几分钟。

如果查询存在适当的索引, MongoDB 可以使用该索引限制必须检查的文档数.

索引是特殊的数据结构, 它以易于遍历的形式存储集合数据集的一小部分 索引存储特定字段或一组字段的值, 按字段值排序.索引项的排序支持有效的相等匹配和基于范围的查询操作.并且, MongoDB 还可以使用索引中的排序返回排序结果.

MongoDB 使用的是 B Tree, MySQL 使用的是 B+ Tree

4.1、索引的类型

4.1.1、单字段索引

就是在某一个字段上加一个索引 并且排序 1表示升序 -1表示降序
在这里插入图片描述

4.1.2、复合索引

支持多个字段的用户定义索引,即复合索引。
复合索引汇总列出的字段顺序很重要,比如:复合索引中{userid:1,score:;-1}组成,那么索引就首先安userid正序排序,然后在每个userid的值中按score的降序排列
在这里插入图片描述

4.1.3、其他索引

地理空间索引(Geospatial Index)、文本索引(Text Indexes)、哈希索引(HashedIndexes)
地理空间索引(Geospatial Index)
为了支持对地理空间坐标数据的有效查询, MongoDB 提供了两种特殊的索引: 返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引.

文本索引(Text Indexes)
MongoDB 提供了一种文本索引类型, 支持在集合中搜索字符串内容.这些文本索引不存储特定于语言的停止词(例如 “the”, “a”, “or”), 而将集合中的词作为词干, 只存储根词.

哈希索引(Hashed Indexes)
为了支持基于散列的分片, MongoDB 提供了散列索引类型, 它对字段值的散列进行索引.这些索引在其范围内的值分布更加随机, 但只支持相等匹配, 不支持基于范围的查询

4.2、索引的管理操作

4.2.1、索引的查看

返回一个集合的所有索引的数组

//查看索引
db.collection.getIndexes()

db.comment.getIndexes()

4.2.2、索引的创建

在集合上创建索引
语法:

db.collection.createIndex(keys,options)

在这里插入图片描述
在这里插入图片描述
常用的options

  • unique
  • name

复合索引的创建:

//创建复合索引
db.comment.createIndex({userid:1,nickname:-1})

db.comment.getIndexes()

4.2.2、索引的移除

可以移除指定的索引,也可以移除所有索引
1、指定索引移除

db.comment.dropIndex(index)
-------------------------------
//根据创建条件删除
db.comment.dropIndex({userid:1})
db.comment.getIndexes()
//根据索引名字删除复合索引
db.comment.dropIndex("userid_1_nickname_-1")

//删除全部
db.comment.dropindexes()

4.3、索引的使用

4.3.1、执行计划

分析查询性能,通常使用执行计划(解释计划,Explain Plan)来查看查询的情况,如查询耗费的时间、是否基于索引查询等。
语法
db.collection.find(query,options).explain(options)

db.comment.find({userid:"1003"}).explain()

4.3.2、涵盖查询

查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存。
在这里插入图片描述
详细

5、文章评论编写

1、基本增删改查的API
2、根据文章id查询评论
3、评论点赞

5.1、表结构分析

在这里插入图片描述

5.2、技术选型

Mongodb-driver

SpringDataMongoDB

5.2.1、整合springboot+Mongodb

微服务模块搭建

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath></relativePath>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

创建application.yml

spring:
#  数据源配置
  data:
    mongodb:
      host: localhost
      #数据库
      database: db
      port: 27017

启动类创建:

@SpringBootApplication
public class MainApplication {
    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class,args);
    }
}

5.2.2、文章评论实体类的编写

com.li.po

package com.li.po;

import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.Date;

/**
 * @author 喂S别闹
 * @create 2022/8/4-13:51
 * @Version 1.0
 * @Description: 实体类
 */
@Data
//把一个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;

}

说明:
索引可以大大提升查询效率,一般在查询字段上添加索引,索引的添加可以通过Mongo的命令来添加,也可以在Java的实体类中通过注解添加。

5.2.3、文章评论的crud

创建dao接口

//Comment,String>    comment是实体类   String 是id类型
public interface CommentRepository extends MongoRepository<Comment,String> {
}

2、业务类的编写

@Service
public class CommentService {
    @Autowired
    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<Comment> findCommentList() {
        //调用dao
        return commentRepository.findAll();
    }

    /**
     * 根据id查询评论
     *
     * @param id
     * @return
     */
    public Comment findCommentById(String id) {
        //调用dao
        return commentRepository.findById(id).get();
    }
}

3、测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CommentServiceTest {

    @Autowired
    private CommentService commentService;

    @Test
    public void findCommentList(){
        List<Comment> commentList = commentService.findCommentList();
        commentList.forEach(System.out::println);
    }
    @Test
    public void findCommentById(){
        Comment commentList = commentService.findCommentById("1");
        System.out.println(commentList);
    }

    @Test
    public void testSaveComment(){
        Comment comment = new Comment();
        comment.setArticleid("10002");
        comment.setContent("测试添加的数据");
        comment.setCreatedatetime(LocalDateTime.now());
        comment.setUserid("10036");
        comment.setParentid("3");
        comment.setNickname("一半醒");
        comment.setState("1");
        comment.setReplynum(0);
        comment.setReplynum(0);
        commentService.saveComment(comment);
    }
    }

5.2.4、根据上级id查询文章评论分页列表

CommentRepository新增方法定义

    Page<Comment> findByParentid(String parentid, Pageable pageable); //findByParentid 这是语法格式,前面是findby  后面parentid要与实体类的属性对应

CommentService新增方法

    public Page<Comment> findCommentListByParentid(String parentid,int page,int size){
        return commentRepository.findByParentid(parentid, PageRequest.of(page-1,size));
    }

测试

    @Test
    public void testFindCommentListByParentid(){
        Page<Comment> pageResponse = commentService.findCommentListByParentid("3", 1, 2);
        System.out.println("---总记录数---:"+pageResponse.getTotalElements());
        System.out.println("---当前页数据---:"+pageResponse.getContent());
    }

5.2.5、MongoTemplate实现评论点赞

修改CommentService

 @Autowired
    private MongoTemplate mongoTemplate;
        /**
     * 方法描述
     * @param: id
     * @author: 一半醒
     * @date: 2022/8/4
     * @Description:更新评论点赞数
     */
    public void updateCommentLikeNum(String id){
        //查询条件
        Query query = Query.query(Criteria.where("_id").is(id));
        //更新条件
        Update update = new Update();
        update.inc("likenum");
        mongoTemplate.updateFirst(query,update,Comment.class);
    }

测试

    @Test
   public void testUpdateCommentLikeNum(){
       commentService.updateCommentLikeNum("1");
   }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值