【探花交友】day03—MongoDB基础

目录

课程介绍

1、通用设置

1.1 需求分析

1.2 查询通用设置

1.2 陌生人问题

1.3 通知设置

1.4 黑名单管理

2、MongoDB简介

1.1、MongoDB简介

1.2、MongoDB的特点

1.3 数据类型

3、MongoDB入门

2.1、数据库以及表的操作

2.2、新增数据

2.3、更新数据

2.4、删除数据

2.5、查询数据

2.6、索引

2.7、执行计划

4、SpringData-Mongo

4.1、环境搭建

4.2、完成基本操作

5、今日佳人

5.1、表结构设计

5.2、服务提供者

5.3、代码实现

课程介绍

  • MongoDB环境搭建

  • MongoDB基本CRUD操作

  • 通过JavaApi操作MongoDB

  • SpringBoot整合MongoDB

1、通用设置

1.1 需求分析

1.1.1 需求分析

通用设置,包含探花交友APP基本的软件设置功能。包含:

设置陌生人问题:当平台其他用户想进行在线交流时需要回答陌生人问题。

通用设置:包含一些APP通知设置

黑名单:对于不感兴趣的用户设置黑名单屏蔽骚扰

1.1.2 数据库表

通用设置

CREATE TABLE `tb_settings` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`like_notification` tinyint(4) DEFAULT '1' COMMENT '推送喜欢通知',`pinglun_notification` tinyint(4) DEFAULT '1' COMMENT '推送评论通知',`gonggao_notification` tinyint(4) DEFAULT '1' COMMENT '推送公告通知',`created` datetime DEFAULT NULL,`updated` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='设置表';

问题表

CREATE TABLE `tb_question` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL COMMENT '用户id',`txt` varchar(200) DEFAULT NULL COMMENT '问题内容',`created` datetime DEFAULT NULL,`updated` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `user_id` (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

黑名单

CREATE TABLE `tb_black_list` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`black_user_id` bigint(20) DEFAULT NULL,`created` datetime DEFAULT NULL,`updated` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='黑名单';

1.1.3 搭建提供者环境

实体类

(1) Settings

CREATE TABLE `tb_black_list` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`user_id` bigint(20) DEFAULT NULL,`black_user_id` bigint(20) DEFAULT NULL,`created` datetime DEFAULT NULL,`updated` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='黑名单';

(2)Question

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Question extends BasePojo {private Long id;private Long userId;//问题内容private String txt;}

(3)BlackList

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BlackList extends BasePojo {private Long id;private Long userId;private Long blackUserId;
}

mapper接口

(1)SettingsMapper

public interface SettingsMapper extends BaseMapper<Settings> {
}

(2)QuestionMapper

public interface QuestionMapper extends BaseMapper<Question> {}

(3)BlackListMapper

public interface BlackListMapper extends BaseMapper<BlackList> {}

api接口

(1) SettingApi

package com.tanhua.dubbo.api;import com.tanhua.domain.db.Settings;public interface SettingsApi {}

(2)QuestionApi

package com.tanhua.dubbo.api;import com.tanhua.domain.db.Question;public interface QuestionApi {}

(3)BlackListApi

package com.tanhua.dubbo.api;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.tanhua.domain.db.UserInfo;public interface BlackListApi {}

api服务实现类

(1)SettingServiceImpl

package com.tanhua.dubbo.api;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.domain.db.Settings;
import com.tanhua.dubbo.mapper.SettingsMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;@DubboService
public class SettingsApiImpl implements SettingsApi {@Autowiredprivate SettingsMapper settingsMapper;}

(2)QuestionServiceImpl

package com.tanhua.dubbo.api;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.domain.db.Question;
import com.tanhua.dubbo.mapper.QuestionMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;@DubboService
public class QuestionApiImpl implements QuestionApi {@Autowiredprivate QuestionMapper questionMapper;}

(3)BlackListServiceImpl

package com.tanhua.dubbo.api;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tanhua.domain.db.BlackList;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.dubbo.mapper.BlackListMapper;
import com.tanhua.dubbo.mapper.UserInfoMapper;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;@DubboService
public class BlackListApiImpl implements BlackListApi {@Autowiredprivate BlackListMapper blackListMapper;
}

1.2 查询通用设置

1.2.1 接口文档

1.2.2 代码实现

vo对象

@Data
@NoArgsConstructor
@AllArgsConstructor
public class SettingsVo implements Serializable {private Long id;private String strangerQuestion = "";private String phone;private Boolean likeNotification = true;private Boolean pinglunNotification = true;private Boolean gonggaoNotification = true;}

SettingsController

tanhua-server工程创建SettingsController完成代码编写

@RestController
@RequestMapping("/users")
public class SettingsController {@Autowiredprivate SettingsService settingsService;/*** 查询通用设置*/@GetMapping("/settings")public ResponseEntity settings() {SettingsVo vo = settingsService.settings();return ResponseEntity.ok(vo);}
}

SettingService

tanhua-server工程创建SettingService完成代码编写

@Service
public class SettingsService {@DubboReferenceprivate QuestionApi questionApi;@DubboReferenceprivate SettingsApi settingsApi;@DubboReferenceprivate BlackListApi blackListApi;//查询通用设置public SettingsVo settings() {SettingsVo vo = new SettingsVo();//1、获取用户idLong userId = UserHolder.getUserId();vo.setId(userId);//2、获取用户的手机号码vo.setPhone(UserHolder.getMobile());//3、获取用户的陌生人问题Question question = questionApi.findByUserId(userId);String txt = question == null ? "你喜欢java吗?" : question.getTxt();vo.setStrangerQuestion(txt);//4、获取用户的APP通知开关数据Settings settings = settingsApi.findByUserId(userId);if(settings != null) {vo.setGonggaoNotification(settings.getGonggaoNotification());vo.setPinglunNotification(settings.getPinglunNotification());vo.setLikeNotification(settings.getLikeNotification());}return vo;}
}

QuestionApi

在tanhua-dubbo中的QuestionApiQuestionApiImpl补充方法

@Override
public Question findByUserId(Long userId) {QueryWrapper<Question> qw = new QueryWrapper<>();qw.eq("user_id",userId);return questionMapper.selectOne(qw);
}

SettingApi

在tanhua-dubbo中的SettingApiSettingApiImpl补充方法

//根据用户id查询
public Settings findByUserId(Long userId) {QueryWrapper<Settings> qw = new QueryWrapper<>();qw.eq("user_id",userId);return settingsMapper.selectOne(qw);
}

1.2 陌生人问题

对数据库表进行操作:如果存在数据,更新数据库。如果不存在数据,保存数据库表数据

1.2.1 接口文档

1.2.2 代码实现

SettingsController

/*** 设置陌生人问题*/
@PostMapping("/questions")
public ResponseEntity questions(@RequestBody Map map) {//获取参数String content = (String) map.get("content");settingsService.saveQuestion(content);return ResponseEntity.ok(null);
}

SettingsService

//设置陌生人问题
public void saveQuestion(String content) {//1、获取当前用户idLong userId = UserHolder.getUserId();//2、调用api查询当前用户的陌生人问题Question question = questionApi.findByUserId(userId);//3、判断问题是否存在if(question == null) {//3.1 如果不存在,保存question = new Question();question.setUserId(userId);question.setTxt(content);questionApi.save(question);}else {//3.2 如果存在,更新question.setTxt(content);questionApi.update(question);}
}

QuestionApi

tanhua-dubbo工程中的QuestionApiQuestionApiImpl中添加保存和更新方法

@Override
public void save(Question question) {questionMapper.insert(question);
}@Override
public void update(Question question) {questionMapper.updateById(question);
}

1.3 通知设置

1.3.1 接口文档

通知管理:对通知进行保存或者更新的操作

http://192.168.136.160:3000/project/19/interface/api/280

1.3.2 代码实现

SettingsController

/*** 通知设置*/
@PostMapping("/notifications/setting")
public ResponseEntity notifications(@RequestBody Map map) {//获取参数settingsService.saveSettings(map);return ResponseEntity.ok(null);
}

SettingsService

//通知设置
public void saveSettings(Map map) {boolean likeNotification = (Boolean) map.get("likeNotification");boolean pinglunNotification = (Boolean) map.get("pinglunNotification");boolean gonggaoNotification = (Boolean)  map.get("gonggaoNotification");//1、获取当前用户idLong userId = UserHolder.getUserId();//2、根据用户id,查询用户的通知设置Settings settings = settingsApi.findByUserId(userId);//3、判断if(settings == null) {//保存settings = new Settings();settings.setUserId(userId);settings.setPinglunNotification(pinglunNotification);settings.setLikeNotification(likeNotification);settings.setGonggaoNotification(gonggaoNotification);settingsApi.save(settings);}else {settings.setPinglunNotification(pinglunNotification);settings.setLikeNotification(likeNotification);settings.setGonggaoNotification(gonggaoNotification);settingsApi.update(settings);}
}

SettingsApi

tanhua-dubbo工程中的SettingsApiSettingsApiImpl中添加保存和更新方法

@Override
public void save(Settings settings) {settingsMapper.insert(settings);
}@Override
public void update(Settings settings) {settingsMapper.updateById(settings);
}

1.4 黑名单管理

1.3.1 接口文档

  • 查询黑名单列表

  • 移除黑名单

1.3.2 分页查询

vo对象

tanhua-domain工程的配置分页vo对象

package com.tanhua.domain.vo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;
import java.util.Collections;
import java.util.List;@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {private Integer counts = 0;//总记录数private Integer pagesize;//页大小private Integer pages = 0;//总页数private Integer page;//当前页码private List<?> items = Collections.emptyList(); //列表public PageResult(Integer page,Integer pagesize,int counts,List list) {this.page = page;this.pagesize = pagesize;this.items = list;this.counts = counts;this.pages = counts % pagesize == 0 ? counts / pagesize : counts / pagesize + 1;}}

SettingsController

/*** 分页查询黑名单列表*/
@GetMapping("/blacklist")
public ResponseEntity blacklist(@RequestParam(defaultValue = "1") int page,@RequestParam(defaultValue = "10") int size) {//1、调用service查询PageResult pr = settingsService.blacklist(page,size);//2、构造返回return ResponseEntity.ok(pr);
}/*** 取消黑名单*/
@DeleteMapping("/blacklist/{uid}")
public ResponseEntity deleteBlackList(@PathVariable("uid") Long blackUserId) {settingsService.deleteBlackList(blackUserId);return ResponseEntity.ok(null);
}

SettingService

//分页查询黑名单列表
public PageResult blacklist(int page, int size) {//1、获取当前用户的idLong userId = UserHolder.getUserId();//2、调用API查询用户的黑名单分页列表  Ipage对象IPage<UserInfo> iPage = blackListApi.findByUserId(userId,page,size);//3、对象转化,将查询的Ipage对象的内容封装到PageResult中PageResult pr = new PageResult(page,size,iPage.getTotal(),iPage.getRecords());//4、返回return pr;
}//取消黑名单
public void deleteBlackList(Long blackUserId) {//1、获取当前用户idLong userId = UserHolder.getUserId();//2、调用api删除blackListApi.delete(userId,blackUserId);
}

BlackListApi

@Override
public IPage<UserInfo> findByUserId(Long userId, int page, int size) {//1、构建分页参数对象PagePage pages = new Page(page,size);//2、调用方法分页(自定义编写 分页参数Page,sql条件参数)return userInfoMapper.findBlackList(pages,userId);
}@Override
public void delete(Long userId, Long blackUserId) {QueryWrapper<BlackList> qw = new QueryWrapper<>();qw.eq("user_id",userId);qw.eq("black_user_id",blackUserId);blackListMapper.delete(qw);
}

UserInfoMapper

public interface UserInfoMapper extends BaseMapper<UserInfo> {@Select("select * from tb_user_info where id in (\n" +"  SELECT black_user_id FROM tb_black_list where user_id=#{userId}\n" +")")IPage<UserInfo> findBlackList(@Param("pages") Page pages, @Param("userId") Long userId);
}

MybatisPlusConfig

tanhua-dubbo-db引导类开启mybatis-plus分页插件支持

public interface UserInfoMapper extends BaseMapper<UserInfo> {@Select("select * from tb_user_info where id in (\n" +"  SELECT black_user_id FROM tb_black_list where user_id=#{userId}\n" +")")IPage<UserInfo> findBlackList(@Param("pages") Page pages, @Param("userId") Long userId);
}

使用mybatis-plus的分页:

  • 创建分页对象:Page,指定当前页和每页查询条数

  • 基础查询:mapper.selectPage(page,查询条件)

  • 自定义查询:Ipage 方法名称(Page对象,xxx查询条件)

2、MongoDB简介

对于社交类软件的功能,我们需要对它的功能特点做分析:

  • 数据量会随着用户数增大而增大

  • 读多写少

  • 价值较低

  • 非好友看不到其动态内容

  • 地理位置的查询

  • ……

针对以上特点,我们来分析一下:

  • mysql:关系型数据库(效率低)

  • redis:redis缓存(微博,效率高,数据格式不丰富)

  • 对于数据量大而言,显然不能够使用关系型数据库进行存储,我们需要通过MongoDB进行存储

  • 对于读多写少的应用,需要减少读取的成本

    • 比如说,一条SQL语句,单张表查询一定比多张表查询要快

探花交友

  • mongodb:存储业务数据(圈子,推荐的数据,小视频数据,点赞,评论等)

  • redis:承担的角色是缓存层(提升查询效率)

  • mysql:存储和核心业务数据,账户

1.1、MongoDB简介

MongoDB:是一个高效的非关系型数据库(不支持表关系:只能操作单表)

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的,它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。

MongoDB最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

官网:MongoDB: The Developer Data Platform | MongoDB

1.2、MongoDB的特点

MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:

  1. 面向集合存储,易于存储对象类型的数据

  2. 模式自由

  3. 支持动态查询

  4. 支持完全索引,包含内部对象

  5. 支持复制和故障恢复

  6. 使用高效的二进制数据存储,包括大型对象(如视频等)

  7. 自动处理碎片,以支持云计算层次的扩展性

  8. 支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl及C++语言的驱动程 序, 社区中也提供了对Erlang及.NET 等平台的驱动程序

  9. 文件存储格式为 BSON(一种 JSON 的扩展)

1.2.1、通过docker安装MongoDB

在课程资料的虚拟机中已经提供了MongoDB的镜像和容器,我们只需要使用简单的命令即可启动

#进入base目录
cd /root/docker-file/base/
#批量创建启动容器,其中已经包含了redis,zookeeper,mongodb容器
docker-compose up -d
#查看容器
docker ps -a

可以看到mongoDB已经启动,对外暴露了27017的操作端口

1.2.2、MongoDB体系结构

MongoDB 的逻辑结构是一种层次结构。主要由: 文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面 向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。

  1. MongoDB 的文档(document),相当于关系数据库中的一行记录。

  2. 多个文档组成一个集合(collection),相当于关系数据库的表。

  3. 多个集合(collection),逻辑上组织在一起,就是数据库(database)。

  4. 一个 MongoDB 实例支持多个数据库(database)。 文档(document)、集合(collection)、数据库(database)的层次结构如下图:

为了更好的理解,下面与SQL中的概念进行对比:

SQL术语/概念MongoDB术语/概念解释/说明
databasedatabase数据库
tablecollection数据库表/集合
rowdocument表中的一条数据
columnfield数据字段/域
indexindex索引
table joins表连接,MongoDB不支持
primary keyprimary key主键,MongoDB自动将_id字段设置为主键

1.3 数据类型

  • 数据格式:BSON {aa:bb}

  • null:用于表示空值或者不存在的字段,{“x”:null}

  • 布尔型:布尔类型有两个值true和false,{“x”:true}

  • 数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用 NumberInt(4字节符号整数)或NumberLong(8字节符号整数), {“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}

  • 字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}

  • 日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}

  • 正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相 同,{“x”:/[abc]/}

  • 数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}

  • 内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}

  • 对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }

  • 二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要 将非utf-字符保存到数据库中,二进制数据是唯一的方式。

3、MongoDB入门

2.1、数据库以及表的操作

#查看所有的数据库
> show dbs#通过use关键字切换数据库
> use admin#创建数据库
#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
> use testdb> show dbs #并没有创建数据库> db.user.insert({id:1,name:'zhangsan'})  #插入数据> show dbs#查看表
> show tables> show collections#删除集合(表)
> db.user.drop()
true  #如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。#删除数据库
> use testdb #先切换到要删除的数据中> db.dropDatabase()  #删除数据库

2.2、新增数据

在MongoDB中,存储的文档结构是一种类似于json的结构,称之为bson(全称为:Binary JSON)。

#插入数据
#语法:db.表名.insert(json字符串)> db.user.insert({id:1,username:'zhangsan',age:20})> db.user.find()  #查询数据

2.3、更新数据

update() 方法用于更新已存在的文档。语法格式如下:

db.collection.update(<query>,<update>,[upsert: <boolean>,multi: <boolean>,writeConcern: <document>]
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。

  • update : update的对象和一些更新的操作符(如$,$inc.$set)等,也可以理解为sql update查询内set后面的

  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。

  • multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。

  • writeConcern :可选,抛出异常的级别。

#查询全部
> db.user.find()#更新数据
> db.user.update({id:1},{$set:{age:22}}) #注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)

2.4、删除数据

通过remove()方法进行删除数据,语法如下:

db.collection.remove(<query>,{justOne: <boolean>,writeConcern: <document>}
)

参数说明:

  • query :(可选)删除的文档的条件。

  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。

  • writeConcern :(可选)抛出异常的级别。

实例:

#删除数据
> db.user.remove({})#插入4条测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})> db.user.remove({age:22},true)#删除所有数据
> db.user.remove({})

2.5、查询数据

MongoDB 查询数据的语法格式如下:

db.user.find([query],[fields])
  • query :可选,使用查询操作符指定查询条件

  • fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。

条件查询:

操作格式范例RDBMS中的类似语句
等于{<key>:<value>}db.col.find({"by":"黑马程序员"}).pretty()where by = '黑马程序员'
小于{<key>:{$lt:<value>}}db.col.find({"likes":{$lt:50}}).pretty()where likes < 50
小于或等于{<key>:{$lte:<value>}}db.col.find({"likes":{$lte:50}}).pretty()where likes <= 50
大于{<key>:{$gt:<value>}}db.col.find({"likes":{$gt:50}}).pretty()where likes > 50
大于或等于{<key>:{$gte:<value>}}db.col.find({"likes":{$gte:50}}).pretty()where likes >= 50
不等于{<key>:{$ne:<value>}}db.col.find({"likes":{$ne:50}}).pretty()where likes != 50

实例:

#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})db.user.find()  #查询全部数据
db.user.find({},{id:1,username:1})  #只查询id与username字段
db.user.find().count()  #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1)  #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照id倒序排序,-1为倒序,1为正序

2.6、索引

索引通常能够极大的提高查询的效率,如果没有索引,MongoDB在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。

这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。

索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构

#创建索引
> db.user.createIndex({'age':1})#查看索引
> db.user.getIndexes()
[{"v" : 2,"key" : {"_id" : 1},"name" : "_id_","ns" : "testdb.user"}
]
#说明:1表示升序创建索引,-1表示降序创建索引。

2.7、执行计划

MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。

#插入1000条数据
for(var i=1;i<1000;i++)db.user.insert({id:100+i,username:'name_'+i,age:10+i})#查看执行计划
> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()#测试没有使用索引
> db.user.find({username:'zhangsan'}).explain()#winningPlan:最佳执行计划
#"stage" : "FETCH", #查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询

4、SpringData-Mongo

Spring-data对MongoDB做了支持,使用spring-data-mongodb可以简化MongoDB的操作,封装了底层的mongodb-driver。

地址:Spring Data MongoDB

使用Spring-Data-MongoDB很简单,只需要如下几步即可:

  • 导入起步依赖

  • 编写配置信息

  • 编写实体类(配置注解 @Document,@Id)

  • 操作mongodb

    • 注入MongoTemplate对象,完成CRUD操作

    • 编写Repository接口,注入接口完成基本Crud操作

4.1、环境搭建

第一步,导入依赖:

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

第二步,编写application.yml配置文件

spring:data:mongodb:uri: mongodb://192.168.136.160:27017/test

第三步,编写启动类

package com.tanhua.mongo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class MongoApplication {public static void main(String[] args) {SpringApplication.run(MongoApplication.class, args);}
}

4.2、完成基本操作

第一步,编写实体类

package com.tanhua.mongo.domain;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(value="person")
public class Person {private ObjectId id;private String name;private int age;private String address;}

第二步,通过MongoTemplate完成CRUD操作

package cn.itcast.mongo.test;import cn.itcast.mongo.MongoApplication;
import cn.itcast.mongo.domain.Person;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
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.test.context.junit4.SpringRunner;import java.util.List;@RunWith(SpringRunner.class)
@SpringBootTest(classes = MongoApplication.class)
public class MongoTest {/*** SpringData-mongodb操作*    1、配置实体类*    2、实体类上配置注解(配置集合和对象间的映射关系)*    3、注入MongoTemplate对象*    4、调用对象方法,完成数据库操作*/@Autowiredprivate MongoTemplate mongoTemplate;//保存@Testpublic void testSave() {for (int i = 0; i < 10; i++) {Person person = new Person();person.setId(ObjectId.get()); //ObjectId.get():获取一个唯一主键字符串person.setName("张三"+i);person.setAddress("北京顺义"+i);person.setAge(18+i);mongoTemplate.save(person);}}//查询-查询所有@Testpublic void testFindAll() {List<Person> list = mongoTemplate.findAll(Person.class);for (Person person : list) {System.out.println(person);}}@Testpublic void testFind() {//查询年龄小于20的所有人Query query = new Query(Criteria.where("age").lt(20)); //查询条件对象//查询List<Person> list = mongoTemplate.find(query, Person.class);for (Person person : list) {System.out.println(person);}}/*** 分页查询*/@Testpublic void testPage() {Criteria criteria = Criteria.where("age").lt(30);//1、查询总数Query queryCount = new Query(criteria);long count = mongoTemplate.count(queryCount, Person.class);System.out.println(count);//2、查询当前页的数据列表, 查询第二页,每页查询2条Query queryLimit = new Query(criteria).limit(2)//设置每页查询条数.skip(2) ; //开启查询的条数 (page-1)*sizeList<Person> list = mongoTemplate.find(queryLimit, Person.class);for (Person person : list) {System.out.println(person);}}/*** 更新:*    根据id,更新年龄*/@Testpublic void testUpdate() {//1、条件Query query = Query.query(Criteria.where("id").is("5fe404c26a787e3b50d8d5ad"));//2、更新的数据Update update = new Update();update.set("age", 20);mongoTemplate.updateFirst(query, update, Person.class);}@Testpublic void testRemove() {Query query = Query.query(Criteria.where("id").is("5fe404c26a787e3b50d8d5ad"));mongoTemplate.remove(query, Person.class);}
}

5、今日佳人

在用户登录成功后,就会进入首页,首页中有今日佳人、推荐好友、探花、搜附近等功能。

今日佳人,会推荐缘分值最大的用户,进行展现出来。缘分值的计算是由用户的行为进行打分,如:点击、点赞、评论、学历、婚姻状态等信息组合而成的。

实现:我们先不考虑推荐的逻辑,假设现在已经有推荐的结果,我们只需要从结果中查询到缘分值最高的用户就可以了。至于推荐的逻辑以及实现,我们将后面的课程中讲解。

流程:

5.1、表结构设计

#表结构  recommend_user
{"userId":1001,  #推荐的用户id"toUserId":1002, #用户id"score":90,  #推荐得分"date":"2019/1/1" #日期
}

在MongoDB中只存储用户的id数据,其他的数据需要通过接口查询。

5.2、服务提供者

5.2.0、导入依赖

找到tanhua-domain模块的pom.xml打开mongo的依赖

5.2.1、实体类

@AllArgsConstructor
@NoArgsConstructor
@Data
@Document(collection = "recommend_user")
public class RecommendUser implements java.io.Serializable {private ObjectId id; //主键idprivate Long userId; //推荐的用户idprivate Long toUserId; //用户idprivate Double score =0d; //推荐得分private String date; //日期
}

5.2.2、RecommendUserApi接口

public interface RecommendUserApi {RecommendUser queryWithMaxScore(Long toUserId);
}

5.2.3、RecommendUserApiImpl

@DubboService
public class RecommendUserApiImpl  implements RecommendUserApi {@Autowiredprivate MongoTemplate mongoTemplate;//查询今日佳人public RecommendUser queryWithMaxScore(Long toUserId) {//根据toUserId查询,根据评分score排序,获取第一条//构建CriteriaCriteria criteria = Criteria.where("toUserId").is(toUserId);//构建Query对象Query query = Query.query(criteria).with(Sort.by(Sort.Order.desc("score"))).limit(1);//调用mongoTemplate查询return mongoTemplate.findOne(query,RecommendUser.class);}
}

5.2.4、application配置

server:port: 18082
spring:application:name: tanhua-dubbo-mongocloud:nacos:discovery:server-addr: 192.168.136.160:8848data:mongodb:uri: mongodb://192.168.136.160:27017/tanhua        
dubbo:protocol:name: dubboport: 20882registry:address: spring-cloud://localhostscan:base-packages: com.tanhua.dubbo.api  #dubbo中包扫描

5.2.5 启动类

package com.tanhua.dubbo;import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class DubboMongoApplication {public static void main(String[] args) {SpringApplication.run(DubboMongoApplication.class,args);}
}

5.3、代码实现

5.3.1、接口说明

地址:http://192.168.136.160:3000/project/19/interface/api/100

5.3.2、TanhuaController

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {@Autowiredprivate TanhuaService tanhuaService;//今日佳人@GetMapping("/todayBest")public ResponseEntity todayBest() {TodayBest vo = tanhuaService.todayBest();return ResponseEntity.ok(vo);}
}

5.3.3、TanhuaService

@Service
public class TanhuaService {@DubboReferenceprivate RecommendUserApi recommendUserApi;@DubboReferenceprivate UserInfoApi userInfoApi;@DubboReferenceprivate QuestionApi questionApi;@Autowiredprivate HuanXinTemplate template;//查询今日佳人数据public TodayBest todayBest() {//1、获取用户idLong userId = UserHolder.getUserId();//2、调用API查询RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);if(recommendUser == null) {recommendUser = new RecommendUser();recommendUser.setUserId(1l);recommendUser.setScore(99d);}//3、将RecommendUser转化为TodayBest对象UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());TodayBest vo = TodayBest.init(userInfo, recommendUser);//4、返回return vo;}
}

5.3.4、vo对象

package com.tanhua.domain.vo;import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.mongo.RecommendUser;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;/*** 今日佳人*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TodayBest {private Long id; //用户idprivate String avatar;private String nickname;private String gender; //性别 man womanprivate Integer age;private String[] tags;private Long fateValue; //缘分值/*** 在vo对象中,补充一个工具方法,封装转化过程*/public static TodayBest init(UserInfo userInfo, RecommendUser recommendUser) {TodayBest vo = new TodayBest();BeanUtils.copyProperties(userInfo,vo);if(userInfo.getTags() != null) {vo.setTags(userInfo.getTags().split(","));}vo.setFateValue(recommendUser.getScore().longValue());return vo;}
}

5.3.5、解决MongoDB启动bug

在项目中,添加了mongo的依赖的话,springboot就会自动去连接本地的mongo,由于他连接不上会导致出错。

解决有2种方案:

  • 排除掉mongo的依赖

  • springboot中添加排除自动配置的注解

    package com.tanhua.server;import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
    import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;@SpringBootApplication(exclude = {MongoAutoConfiguration.class,MongoDataAutoConfiguration.class
    }) //排除mongo的自动配置
    public class TanhuaServerApplication {public static void main(String[] args) {SpringApplication.run(TanhuaServerApplication.class,args);}
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/497369.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot + Vue3实现的在线商品竞拍管理系统源码+文档

前言 基于Spring Boot Vue3实现的在线商品竞拍管理系统是一种现代化的前后端分离架构的应用程序&#xff0c;它结合了Java后端框架Spring Boot和JavaScript前端框架Vue.js的最新版本&#xff08;Vue 3&#xff09;。该系统允许用户在线参与商品竞拍&#xff0c;并提供管理后台…

JVM学习-内存结构(二)

一、堆 1.定义 2.堆内存溢出问题 1.演示 -Xmx设置堆大小 3.堆内存的诊断 3.1介绍 1&#xff0c;2都是命令行工具&#xff08;可直接在ideal运行时&#xff0c;在底下打开终端&#xff0c;输入命令&#xff09; 1可以拿到Java进程的进程ID&#xff0c;2 jmap只能查询某一个时…

在线学习平台-项目技术点-后台

目录 1、主键生成策略 1.1自动增长-AUTO INCREMENT 1.2UUID 1.3Redis生成ID 2、MyBatis-plus 2.1自动填充 2.2悲观锁、乐观锁 2.3性能分析插件 3.ResponseBody和RequestBody 4.es6语法 4.1let变量和const变量 4.2解构赋值&#xff08;数组和对象解构 4.3模板字符串…

Redis 实战篇 ——《黑马点评》(上)

《引言》 在进行了前面关于 Redis 基础篇及其客户端的学习之后&#xff0c;开始着手进行实战篇的学习。因内容很多&#xff0c;所以将会分为【 上 中 下 】三篇记录学习的内容与在学习的过程中解决问题的方法。Redis 实战篇的内容我写的很详细&#xff0c;为了能写的更好也付出…

MySQL数据库——常见的几种锁分类

详细介绍MySQL的几种常见锁分类&#xff0c;如&#xff1a;表级锁、行级锁、页面锁、悲观锁、乐观锁、共享锁、排他锁、Gap-锁等。 文章目录 按锁粒度分表级锁行级锁页面锁锁与索引关系 按加锁机制分【逻辑上的锁】悲观锁乐观锁版本号机制CAS&#xff08;Compare and Swap&…

数据库sql语句单表查询

简单的增删改查操作 select count(*) from user where accountadmin and password123456 select count(*) from user where account"admin" insert into user(account,password) values ("admin","777") update user set password "666&…

OpenCV和PyQt的应用

1.创建一个 PyQt 应用程序&#xff0c;该应用程序能够&#xff1a; 使用 OpenCV 加载一张图像。在 PyQt 的窗口中显示这张图像。提供四个按钮&#xff08;QPushButton&#xff09;&#xff1a; 一个用于将图像转换为灰度图一个用于将图像恢复为原始彩色图一个用于将图像进行翻…

电路元件与电路基本定理

电流、电压和电功率 电流 1 定义&#xff1a; 带电质点的有序运动形成电流 。 单位时间内通过导体横截面的电量定义为电流强度&#xff0c; 简称电流&#xff0c;用符号 i 表示&#xff0c;其数学表达式为&#xff1a;&#xff08;i单位&#xff1a;安培&#xff08;A&#x…

win11中win加方向键失效的原因

1、可能是你把win键锁了&#xff1a; 解决办法&#xff1a;先按Fn键&#xff0c;再按win键 2、可能是可能是 贴靠窗口设置 中将贴靠窗口关闭了&#xff0c;只需要将其打开就好了

十二月第五周python

第一个程序&#xff0c;熟悉转换器&#xff0c;把加法计算器变成exe# // 1,制作加法计算器&#xff0c; # 输入两个数字得到相加结果并输出aint(input("输入数字&#xff1a;"))#int()是把输入的内容转换成整数&#xff0c; bint(input("输入数字&#xff1a;&…

pyqt和pycharm环境搭建

安装 python安装&#xff1a; https://www.python.org/downloads/release/python-3913/ python3.9.13 64位(记得勾选Path环境变量) pycharm安装&#xff1a; https://www.jetbrains.com/pycharm/download/?sectionwindows community免费版 换源&#xff1a; pip config se…

Lottie动画源码解析

Lottie是一个很成熟的开源动画框架&#xff0c;它支持直接使用从AE导出的动画文件&#xff0c;在不同平台均可快速使用&#xff0c;大大减轻了程序员的工作量&#xff0c;也让复杂的动画成为可能。该动画文件使用Json格式来描述内容&#xff0c;可以大大缩减文件的体积。在Andr…

Cadence学习笔记 16 HDMI接口布局

基于Cadence 17.4&#xff0c;四层板4路HDMI电路 更多Cadence学习笔记&#xff1a;Cadence学习笔记 1 原理图库绘制Cadence学习笔记 2 PCB封装绘制Cadence学习笔记 3 MCU主控原理图绘制Cadence学习笔记 4 单片机原理图绘制Cadence学习笔记 5 四路HDMI原理图绘制Cadence学习笔记…

微服务篇-深入了解 MinIO 文件服务器(你还在使用阿里云 0SS 对象存储图片服务?教你使用 MinIO 文件服务器:实现从部署到具体使用)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 MinIO 文件服务器概述 1.1 MinIO 使用 Docker 部署 1.2 MinIO 控制台的使用 2.0 使用 Java 操作 MinIO 3.0 使用 minioClient 对象的方法 3.1 判断桶是否存在 3.2…

logback之pattern详解以及源码分析

目录 &#xff08;一&#xff09;pattern关键字介绍 &#xff08;二&#xff09;源码分析 &#xff08;一&#xff09;pattern关键字介绍 %d或%date&#xff1a;表示日期&#xff0c;可配置格式化%d{yyyy-MM-dd HH:mm:ss} %r或%relative&#xff1a;也是日期&#xff0c;不过…

【期末复习】JavaEE(下)

1. MVC开发模式 1.1. 运行流程 1.2. SpringMVC 核心组件 1.3. 注解解释 2. ORM与MyBatis 2.1. ORM—对象关系映射 2.2. MyBatis 2.2.1. 创建步骤 会话是单例的&#xff0c;不能跨方法。&#xff08;单例的原因主要是从数据安全角度出发&#xff09; import org.apache.ibatis…

作业帮基于 Apache DolphinScheduler 3_0_0 的缺陷修复与优化

文|作业帮大数据团队&#xff08;阮文俊、孙建业&#xff09; 背 景 基于 Apache DolphinScheduler &#xff08;以下简称DolphinScheduler&#xff09;搭建的 UDA 任务调度平台有效支撑了公司的业务数据开发需求&#xff0c;处理着日均百万级别的任务量。 整个 UDA 的架构如…

电脑缺失sxs.dll文件要怎么解决?

一、文件丢失问题&#xff1a;以sxs.dll文件缺失为例 当你在运行某个程序时&#xff0c;如果系统提示“找不到sxs.dll文件”&#xff0c;这意味着你的系统中缺少了一个名为sxs.dll的动态链接库文件。sxs.dll文件通常与Microsoft的.NET Framework相关&#xff0c;是许多应用程序…

Web开发:ORM框架之使用Freesql的分表分页写法

一、自动分表&#xff08;高版本可用&#xff09; 特性写法 //假如是按月分表&#xff1a;[Table(Name "log_{yyyyMM}", AsTable "createtime2022-1-1(1 month)")]注意&#xff1a;①需包含log_202201这张表 ②递增规律是一个月一次&#xff0c;确保他们…

【数据结构与算法】单向链表

一、什么是链表 链表由一系列节点组成&#xff0c;每个节点都包含一个 data 域&#xff08;存放数据&#xff09;和一个 next 域&#xff08;指向下一节点&#xff09;。链表中的节点可以按照任意顺序存放在内存中&#xff0c;它们之间并不连续。每个节点都记录了下一个节点的地…