MongoDB集合:
-
Message消息对象
集合有什么字段,取决于保存在其中的数据。
下面这张表格是
Message
集合中JSON数据的结构要求:字段 类型 备注 _id UUID 自动生成的主键值 uuid UUID UUID值,并且设置有唯一性索引,防止消息被重复消费 senderId Integer 发送者ID,就是用户ID。如果是系统自动发出,这个ID值是0 senderPhoto String 发送者的头像URL。在消息页面要显示发送人的头像 senderName String 发送者名称,也就是用户姓名。在消息页面要显示发送人的名字 msg String 消息正文 sendTime Date 发送时间 -
Message_ref消息接收对象
虽然message集合记录的是消息,里面有接受者ID,但是如果是群发消息,那么接受者ID是空值。这时候就需要用上
message_ref
集合来记录接收人和已读状态。字段 类型 备注 _id UUID 主键 messageId UUID message记录的_id receiverId String 接收人ID readFlag Boolean 是否已读 lastFlag Boolean 是否为新接收的消息 -
执行两个集合的联合查询,根据接收人来查询消息,并且按照消息发送时间降序排列,查询前50条记录
db.message.aggregate([ { $set: { "id": { $toString: "$_id" } } }, { $lookup:{ from:"message_ref", localField:"id", foreignField:"messageId", as:"ref" }, }, { $match:{"ref.receiverId": 1} }, { $sort: {sendTime : -1} }, { $skip: 0 }, { $limit: 50 } ])
POJO映射类:
-
在Springboot工程中导入maven依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
-
Spring配置:
spring: data: mongodb: host: #服务器 port: #端口 database: #集合 authentication-database: #用户名 username: #用户名 password: #密码
-
spring-data-mongodb主要有以下注解:
-
@Id:
主键,不可重复,自带索引,可以在定义的列名上标注,需要自己生成并维护不重复的约束。如果自己不设置@Id主键,mongo会自动生成一个唯一主键,并且插入时效率远高于自己设置主键。
-
@Document
标注在实体类上,类似于hibernate的entity注解,标明由mongo来维护该表。
-
@Indexed
声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。
唯一索引的话是@Indexed(unique = true)。
-
-
MessageEntity(Message实体类)
@Data @Document(collection = "message") public class MessageEntity implements Serializable { @Id private String _id; @Indexed(unique = true) private String uuid; @Indexed private Integer senderId; private String senderPhoto; private String senderName; @Indexed private Date sendTime; private String msg; }
-
MessageRefEntity(Message_ref实体类)
@Document(collection = "message_ref") @Data public class MessageRefEntity implements Serializable { @Id private String _id; @Indexed private String messageId; @Indexed private Integer receiverId; @Indexed private Boolean readFlag; @Indexed private Boolean lastFlag; }
持久层:
-
就像使用JDBC操作关系型数据库,RedisTemplate操作redis,对应的mongodb也有其操作对象:
MongoTemplate
// 查询Message文档的全部数据 mongoTemplate.findAll(MessageEntity.class); //查询Message文档id为id的数据 mongoTemplate.findById(<id>, MessageEntity.class); //根据query内的查询条件查询 mongoTemplate.find(query, MessageEntity.class); //修改 mongoTemplate.upsert(query, update, MessageEntity.class); //删除 mongoTemplate.remove(query, MessageEntity.class); //新增: mongoTemplate.insert(messageEntity);
具体api查看官方文档:MongoTemplate
-
MessageDao:
@Repository @Slf4j public class MessageDao { @Autowired private MongoTemplate mongoTemplate; /** * 存入消息主体 * * @param entity * @return */ public String insert(MessageEntity entity) { //mongodb里面存储的是gmt时间,需要将当前时间换成格林尼治时间 //gmt为0点 北京时间为8点,所以存数据数据得-8小时 Date sendTime = entity.getSendTime(); sendTime = DateUtil.offset(sendTime, DateField.HOUR, 8); entity.setSendTime(sendTime); entity = mongoTemplate.insert(entity); return entity.get_id(); } /** * 查询集合中消息及其对应的消息接收对象 * * @param userId * @param start * @param length * @return */ //相当用java代码写: //db.message.aggregate([ // { // $set: { // "id": { $toString: "$_id" } // } // }, // { // $lookup:{ // from:"message_ref", // localField:"id", // foreignField:"messageId", // as:"ref" // }, // }, // { $match:{"ref.receiverId": 1} }, // { $sort: {sendTime : -1} }, // { $skip: 0 }, // { $limit: 50 } //]) public List<HashMap> searchMessageByPage(int userId, long start, int length) { JSONObject json = new JSONObject(); json.set("$toString", "$_id"); Aggregation aggregation = Aggregation.newAggregation( Aggregation.addFields().addField("id").withValue(json).build(), Aggregation.lookup("message_ref", "id", "messageId", "ref"), Aggregation.match(Criteria.where("ref.receiverId").is(userId)), Aggregation.sort(Sort.by(Sort.Direction.DESC, "sendTime")), Aggregation.skip(start), Aggregation.limit(length) ); AggregationResults<HashMap> results = mongoTemplate.aggregate(aggregation, "message", HashMap.class); List<HashMap> list = results.getMappedResults(); list.forEach(one -> { List<MessageRefEntity> refList = (List<MessageRefEntity>) one.get("ref"); MessageRefEntity entity = refList.get(0); boolean readFlag = entity.getReadFlag(); String refId = entity.get_id(); one.remove("ref"); one.put("readFlag", readFlag); one.put("refId", refId); one.remove("_id"); //把格林尼治时间转换成北京时间 Date sendTime = (Date) one.get("sendTime"); sendTime = DateUtil.offset(sendTime, DateField.HOUR, -8); String today = DateUtil.today(); //如果是今天的消息,只显示发送时间,不需要显示日期 if (today.equals(DateUtil.date(sendTime).toDateStr())) { one.put("sendTime", DateUtil.format(sendTime, "HH:mm")); } //如果是以往的消息,只显示日期,不显示发送时间 else { one.put("sendTime", DateUtil.format(sendTime, "yyyy/MM/dd")); } }); return list; } public HashMap searchMessageById(String id){ HashMap map = mongoTemplate.findById(id, HashMap.class, "message"); Date sendTime = (Date) map.get("sendTime"); //将GMT时间换成北京时间进行展示 sendTime = DateUtil.date(sendTime).offset(DateField.HOUR,-8); map.replace("sendTime",DateUtil.format(sendTime,"yyyy-MM-dd HH:mm")); return map; } }
-
MessageRefDao:
@Repository @Slf4j public class MessageRefDao { @Autowired private MongoTemplate mongoTemplate; /** * 插入消息对象 * * @param entity * @return */ public String insert(MessageRefEntity entity) { entity = mongoTemplate.insert(entity); return entity.get_id(); } /** * 查询未读消息 * * @param userId * @return */ public long searchUnreadCount(int userId) { Query query = new Query(); query.addCriteria(Criteria.where("readFlag").is(false).and("receiverId").is(userId)); long count = mongoTemplate.count(query, MessageRefEntity.class); return count; } /** * 查询新接收消息数量 * * @return */ public long searchLastCount(int userId) { Query query = new Query(); query.addCriteria(Criteria.where("lastFlag").is(true).and("receiverId").is(userId)); Update update = new Update(); update.set("lastFlag", false); UpdateResult result = mongoTemplate.updateMulti(query, update, "message_ref"); long rows = result.getModifiedCount(); log.debug("※此时修改了" + rows + "条message_ref记录"); return rows; } public long deleteMessageRefById(String id){ Query query = new Query(); query.addCriteria(Criteria.where("_id").is(id)); DeleteResult result = mongoTemplate.remove(query, "message_ref"); long rows = result.getDeletedCount(); log.debug("※此时删除了" + rows + "条message_ref记录"); return rows; } /** * 删除某个用户的全部消息 * @param userId * @return */ public long deleteUserMessageRef(int userId){ Query query = new Query(); query.addCriteria(Criteria.where("receiverId").is(userId)); DeleteResult result = mongoTemplate.remove(query, "message_ref"); long rows = result.getDeletedCount(); log.debug("※此时一共删除了" + rows + "条message_ref记录"); return rows; } /** * 把未读消息变已读 * @param id * @return */ public long updateUnreadMessage(String id) { Query query = new Query(); query.addCriteria(Criteria.where("_id").is(id)); Update update = new Update(); update.set("readFlag", true); UpdateResult result = mongoTemplate.updateFirst(query, update, "message_ref"); long rows = result.getModifiedCount(); log.debug("※此时查阅了" + rows + "条message_ref记录"); return rows; } }