资讯专栏INFORMATION COLUMN

spring-data-mongodb查询使用的一些总结

FuisonDesign / 2254人阅读

摘要:踩到许多坑,记录下一些基于的东西吧首先。王大锤那么查询的时候,如果要根据查询班级怎么办,的查询也非常简单。详情可以查看官方文档用法

刚接触mongodb不久。踩到许多坑,记录下一些基于spring-data-mongodb的东西吧

首先。应该了解下什么情况下使用mongodb,什么情况下用mysql:

业务需要事物,使用mysql,因为mongodb不支持事物

数据量大,但是数据本身价值不大,使用mongodb

数据是非结构化的,且数据量大,使用mongodb

业务未来走向不明确,使用mongodb,方便扩展

链接:csdn上关于什么时候使用mongodb的博客

简单使用

下面开始接入spring-data-mongodb
使用maven和spring-boot,pom文件里引入依赖即可

</>复制代码

  1. org.springframework.boot
  2. spring-boot-starter-data-mongodb

在java代码里,向集合的实体类上面加上@Document,表示这个类被spring-data-mongodb标识了,可以映射成mongodb里的一个集合,默认名字就是类名,也可以取别名@Document(collection="alias"),示例如下:

</>复制代码

  1. @Document
  2. public class Example{
  3. private String id;
  4. private String picture;
  5. }

注意,String类型的id属性不可缺少,因为mongodb的每个文档都要有一个id(也可以是其他类型的Id,详情可以去官方文档看看),setget方法我就不贴了,用lombok更方便。
这里就可以直接new 一个Example保存了,所以现在建个Repositry用于保存数据
非常简单只要继承一个接口就可以
public interface ExampleRepository extends CrudRepository {}
这里第一个泛型是上面的文档对象实体,第二个泛型是文档的id类型
然后就可以直接用exampleRepositry.save(example)保存文档了。简单的介绍就到这里


自定义实现复杂查询,修改等操作

定义一个Repository类,并加上@Repository注解,然后添加自己的方法就可以了,下面上代码

</>复制代码

  1. @Repository
  2. public class ExampleAdvancedRepository {
  3. @Autowired
  4. private MongoOperations mongoOperations;
  5. public boolean updateAlias(String id, String alias) {
  6. return mongoOperations.updateFirst(
  7. query(where("id").is(id)),
  8. new Update().set("alias", alias),
  9. Example.class).isUpdateOfExisting();
  10. }
  11. }

简单的一个实例,根据Id修改别名,这里一点要说的就是这个id属性我们传入进去是String类型,但是monogdbTemplate会将这个id转成ObjectId,但是只局限于这个文档属性名叫id的,如果是其他属性比如userId,虽然也是ObjectId,但是用where("userId").is(userId)这样查询是失败的,因为这里的userId并没有转成ObjectId,正确的做法是where("userId").is(new ObjectId(userId))

数组操作:
增:只要push进数组里就行

</>复制代码

  1. public boolean createReply(Reply reply) {
  2. return mongoOperations.updateFirst(
  3. query(where("id").is(reply.getCommentId())),
  4. new Update()
  5. .inc("total_replies", 1)
  6. .push("replies", reply),
  7. Comment.class).isUpdateOfExisting();
  8. }

删:删除操作构建一个带id的DB对象,然后丢进pull方法里就行了,代码如下

</>复制代码

  1. public boolean deleteReply(String commentId, String replyId) {
  2. BasicDBObject object = new BasicDBObject();
  3. object.put("id", replyId);
  4. return mongoOperations.updateFirst(
  5. query(where("id").is(commentId)),
  6. new Update()
  7. .inc("total_replies", -1)
  8. .pull("replies", object),
  9. Comment.class).isUpdateOfExisting();
  10. }

这个示例删除了数组里某个对象,所以要使用传入一个删除对象的id,如果数组里存的就是数字,或者字符串就可以直接pull("users","张三")
改:

数组里的对象修改,用占位符即可,代码如下

</>复制代码

  1. public boolean createReplyVote(String commentId, String replyId, String userId) {
  2. return mongoOperations.updateFirst(
  3. query(where("id").is(commentId).andOperator(
  4. where("replies.id").is(new ObjectId(replyId)))),
  5. new Update()
  6. .addToSet("replies.$.voter_ids", userId)
  7. .inc("replies.$.total_voters", 1),
  8. Comment.class).isUpdateOfExisting();
  9. }

用占位符$表示数组里的某个匹配的元素

数组里嵌套数组,更新里面数组里的某个对象的属性
根据上面的方法,发现要用2个占位符,比如set("replies.$.voters.$.name","李四")但是这种写法是错误的。这种情况在mongodb3.6之前是没办法解决的,只能将数组嵌套数组的结构改变,变成Map的形式,不能出现两个占位符的情况,或者修改设计,将里边的数组拿出来作为独立的文档

索引

建立索引可以使用mongodb的脚本去建立,也可以用spring-data-mongo提供的注解建立索引
下面弄个简单的索引,代码如下:

</>复制代码

  1. @Document
  2. @CompoundIndexes({
  3. @CompoundIndex(def = "{"userId": 1, "createdDate": -1}")
  4. })
  5. public class Example {
  6. private String id;
  7. private String userId;
  8. private Date createdDate;
  9. }

这里建立 了一个简单的聚合索引,根据userId和createdDate建立的索引。

查看索引是否起效果,可以使用explain方法查看执行计划,示例如下
collection结构

</>复制代码

  1. {
  2. "_id" : ObjectId("5b0cc0f2fde29f2ea0641b16"),
  3. "userId" : "1",
  4. "createdDate" : ISODate("1995-09-30T16:00:00.000+0000"),
  5. "gender" : "MALE"
  6. }

执行语句db.Example.find({"userId":"1"}).explain();
可以查看到结果

</>复制代码

  1. {
  2. "queryPlanner": {
  3. "plannerVersion": 1.0,
  4. ...
  5. "winningPlan": {
  6. "stage": "FETCH",
  7. "inputStage": {
  8. "stage": "IXSCAN",
  9. "keyPattern": {
  10. "user_id": 1.0,
  11. "created_date": -1.0
  12. },
  13. "indexName": "user_id_1_created_date_-1",
  14. "isMultiKey": false,
  15. "isUnique": false,
  16. "isSparse": false,
  17. "isPartial": false,
  18. "indexVersion": 1.0,
  19. "direction": "forward",
  20. "indexBounds": {
  21. "user_id": ["["22", "22"]"],
  22. "created_date": ["[MaxKey, MinKey]"]
  23. }
  24. }
  25. },
  26. "rejectedPlans": []
  27. }
  28. ...
  29. }

可以看到关键的信息,winningPlan 表示走了索引,然后是具体的信息,rejectedPlans表示没有走的索引

外键引用@DBRef

在使用mongdb的时候经常会遇到一个集合嵌套了另一个集合的情况,如果不用引用的话,就得自己手动写代码冗余数据,修改的时候就比较麻烦,要同时修改多处。用mongodb提供的$ref 能很好的解决这个问题
首先写个例子

</>复制代码

  1. @Document
  2. public class Clazz{
  3. private String id;
  4. private String name;
  5. @DBRef
  6. private People leader;
  7. }
  8. @Document
  9. public class People{
  10. private String id;
  11. private String name;
  12. private Integer gender;
  13. private Integer age;
  14. }

每个班级都需要个班主任leader,这个时候用外键非常合适使用很简单,只要在要用到外键的字段上,加上@DBRef就可以了。先创建个People集合,保存写people信息,然后再创建Clazz集合,可以发现Clazz存储的时候leader变成了一个引用类型。

</>复制代码

  1. {
  2. "_id" : ObjectId("5b10a741628e881fc8848d21"),
  3. "name" : "王大锤",
  4. "leader" : DBRef("People", ObjectId("5b0cf065fde29f25486bf532")),
  5. }

那么查询的时候,如果要根据leader查询班级怎么办,@DBRef的查询也非常简单。

</>复制代码

  1. public Clazz findByLeaderId(String leaderId) {
  2. return mongoOperations.findOne(
  3. query(where("leader.$id").is(new ObjectId(leaderId))),
  4. GhostFriend.class);
  5. }

这里注意2个地方,第一个就是引用的时候要加上$id,这样才能表示此id是引用,第二个地方就是new ObjectId() 在自定义复杂查询哪里有提到为什么要new ObjectId()

数组操作里有些特殊的场景

1.队列(先进先出)
比如我要保留最新的3个浏览记录,那么就应该建立一个数组,先进的先删除,永远保留3个元素

</>复制代码

  1. public boolean updateHistory(String id,History history) {
  2. return mongoOperations.updateFirst(
  3. query(where("id").is(id)),
  4. new Update()
  5. .push("histories").slice(-3).each(history)
  6. People.class).isUpdateOfExisting();
  7. }

这里利用了slice接收int类型的值,表示截取多少个元素,正值则是从前到后保留,负值表示从后到前保留,each则表示加入数组的元素
这里只是做一个简单的介绍,网上中文资料不多。详情可以查看mongodb官方文档slice用法

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/19268.html

相关文章

  • spring-data-mongodb查询使用一些总结

    摘要:踩到许多坑,记录下一些基于的东西吧首先。王大锤那么查询的时候,如果要根据查询班级怎么办,的查询也非常简单。详情可以查看官方文档用法 刚接触mongodb不久。踩到许多坑,记录下一些基于spring-data-mongodb的东西吧 首先。应该了解下什么情况下使用mongodb,什么情况下用mysql: 业务需要事物,使用mysql,因为mongodb不支持事物 数据量大,但是数据本身...

    jollywing 评论0 收藏0
  • spring-data-mongodb常用操作

    摘要:踩到许多坑,记录下一些基于的东西吧首先。先创建个集合,保存写信息,然后再创建集合,可以发现存储的时候变成了一个引用类型。王大锤那么查询的时候,如果要根据查询班级怎么办,的查询也非常简单。详情可以查看官方文档用法 刚接触mongodb不久。踩到许多坑,记录下一些基于spring-data-mongodb的东西吧 首先。应该了解下什么情况下使用mongodb,什么情况下用mysql: 业...

    Michael_Ding 评论0 收藏0
  • spring-data-mongodb多数据库访问实现

    摘要:最近公司项目需要支持,每个数据库地址不同,需求就是修改配置文件,添加或者删除数据库配置,重启系统后就可以完成,不需要额外修改代码。那怎么来完成数据库的访问的呢核心类是,而变量才是完成访问的关键,而这个其实就是。 最近公司项目需要支持multi-tenancy,每个tenant数据库地址不同,需求就是修改配置文件,添加或者删除数据库配置,重启系统后就可以完成,不需要额外修改代码。 网上搜...

    AaronYuan 评论0 收藏0
  • spring-data-mongodb多数据库访问实现

    摘要:最近公司项目需要支持,每个数据库地址不同,需求就是修改配置文件,添加或者删除数据库配置,重启系统后就可以完成,不需要额外修改代码。那怎么来完成数据库的访问的呢核心类是,而变量才是完成访问的关键,而这个其实就是。 最近公司项目需要支持multi-tenancy,每个tenant数据库地址不同,需求就是修改配置文件,添加或者删除数据库配置,重启系统后就可以完成,不需要额外修改代码。 网上搜...

    pf_miles 评论0 收藏0
  • spring+mongodb整合

    摘要:版本不支持支持为,如果使用并且使用,则会出现提示,编译出错。扫描的仓库目录,会自动扫描扩展了接口的接口进行注入。 mongodb介绍 MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。 MongoD...

    warmcheng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<