关于列表自建索引的一点总结

问题场景

最近接到一个产品需求,需要展示用户的参与的活动列表,这个列表需要根据活动的状态先排序,也即未结束的总是放在前,已结束都放在后面,并且相同状态下按照时间倒序,并支持分页功能

前期缺陷方案

项目使用mongo作为db,一开始看起来似乎挺简单,利用mongo多重order排序出来,再给个lastId作为分页就行了。后面发现产品需求未结束和已结束的时间排序并不是同一个时间,未结束按照创建时间倒序,已结束的按照结束时间倒序,分页中,首页拉去的如果出现了已结束,那么第二页和后面的记录也都会是已结束

思考和处理预案

  • 两种状态按照不同的时间倒序,如果是数据量小的,全都load出来然后在内存中排序就行了,但是现在是已经到要支持分页,数据量较大,这样是不现实的
  • 如果先查出未结束的条数有多少,然后根据传参的page和size来判断load多少条未结束和已结束的数据(分两次读取db,使用各自的时间倒序),似乎也是可行,但是mongo中分页其实最佳实践分页是要采用lastId和size,使用page页码mongo会使用scan全表扫,效率低下,使用page方式一般也只是在管理系统了。但是如果穿lastId上来,又不知道此时要读取第几页,也就无法预估当前页要多少条未结束和已结束的条目,此方案作废。
  • 这里暂时不考虑使用mongo内部js编程进行

回溯问题

这里的场景要求是先根据状态排序,然后再根据不同状态的不同时间排序,最后要支持分页查询。实质是状态-时间1,状态-时间2两条索引导致问题的,在分页上无法进行

解决方案

两条索引导致的问题,那假设现在只有一条索引,也就是假设都按时间1排序,那么事情就简单多了。顺着这个思路,就找到解决方法了——我们手工将两条索引合并。
创建一个新的mongo表,存储结构为:

uid,order,itemId(即用户数据存储的id)

uid和itemId好理解,那这个order怎么来的呢?这个就是我们设计的关键。我们将状态(设定一个数字码,未结束的号码大)拼上时间(这个时间,如果是未结束时创建时间,已结束是世界时间),合成一个数值,然后给这个order加上倒序索引。
这样,当查询uid下分页时候,order就是lastId的值,我们根据这个索引表就能返回有序的itemId,然后再去用户表里面顺序拉出来,这样就实现多状态下不同时间的倒序分页功能了。

效果和代价

这样做完全实现了产品的功能,但也是有代价的,每次查询时候要先查索引表再查实际的数据表,还有,我们新建数据时候,也要同时新建一条索引数据,当状态变化时候,我们也要相应更新索引表数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值