简单描述一下现在问题
我用的mongodb数据库存的数据,里面有个time字段
库里面有很多集合
目前有个接口是分页查询所有集合,然后按照time倒序排序
但是现在这个功能存在问题
mongodb的排序只能通过单集合进行,也就是我现在写了个排序,出现的结果是,单集合倒序排序之后,再把所有数据加在一起,这样又变成了乱序了
我想着大不了再排序一次,也就是单集合排序之后,聚合在一起在进行一次排序,本来以为这个想法没问题,结果,我发现有的集合的时间很新,有的很久没更新了,超过分页长度会有问题
现在分页第二页就出现问题了
除了全都取出来排序以外(数据量太大的时候,会影响性能,一般不考虑),还有什么办法吗?
查了下有聚合管道大概可以,unionWith和sort操作符
我现在想到一个办法,比如分页长度5,把所有集合都取5个出来,然后,排序,取最前面5个,返回给前端,但是这样分页好像也会有问题,会导致漏数据好像
我试试看,这好像能行?
为什么我查的时候找不到
我是什么废物
生成了一个case,大概是这么个意思。
js
// 假设我们要查询第2页,每页10条数据
const page = 2;
const pageSize = 10;
const skip = (page - 1) * pageSize;
db.collection1.aggregate([
// 首先从collection1开始
{ $project: {
// 投影所需字段
_id: 1,
time: 1,
// 其他字段...
// 可以添加一个字段标识来源集合
source: { $literal: "collection1" }
}
},
// 使用$unionWith合并collection2
{ $unionWith: {
coll: "collection2",
pipeline: [
{ $project: {
_id: 1,
time: 1,
// 其他字段...
source: { $literal: "collection2" }
}
}
]
}
},
// 使用$unionWith合并collection3
{ $unionWith: {
coll: "collection3",
pipeline: [
{ $project: {
_id: 1,
time: 1,
// 其他字段...
source: { $literal: "collection3" }
}
}
]
}
},
// 合并后统一按time字段排序
{ $sort: { time: -1 } },
// 分页操作
{ $skip: skip },
{ $limit: pageSize }
])
使用聚合管道+临时集合试试
临时集合可服用,适合频繁的查询, 缺点是需要额外存储空间
db.collection1.aggregate([
{ $unionWith: { coll: "collection2" } },
{ $unionWith: { coll: "collection3" } },
// ... 其他集合
{ $sort: { time: -1 } },
{ $merge: { into: "temp_collection", whenMatched: "replace", whenNotMatched: "insert" } }
]);
// 分页查询临时集合
db.temp_collection.find()
.skip((pageNumber - 1) * pageSize)
.limit(pageSize);
挑战一下需求
能否不做分页,改为上一页,下一页滚动查询。
直接按照时间戳来滚动查询。
滚动查询也要排序
要是mysql啥的还好弄,mongodb这个我有点摸不清头脑
上面佬建议的聚合管道我试了一下,还是有这样的问题,不知道是不是我用的有问题,我再捣鼓一下
查询出来的一页数据量不大 程序二次排序就行了。
emmmm这里的问题是mongodb集合数据time时间不规律,然后数据量也不一致
聚合管道我现在还在摸索,我不太会用
如果不用聚合管道的话,就会出现我描述的问题
二次排序的话,你第一页可能是正常排序的,第二页你会发现你第二页的time比第一页的还新
所以我说挑战一下需求 不要用固定条数分页。
按照时间戳范围 滚动查询
聚合多表 的分页 基本上解决不了顺序问题和深分页性能问题。
而且深分页会非常消耗系统资源。
多少数据量啊 mongodb分表存有点抽象了哦,很难查的,之前也有这种业务,后来优化存储结构和ttl放一个表里了。
先聚合再排序分页 非常吃资源
先排序分页再聚合 顺序有问题
多表合并查询的这个问题是行业通病。
要么改数据结构,要么改需求。要么妥协排序问题。
之前的思路是 每个表排序后取分页个数据出来,比较出第一个分页的数据后,记录最后一个数据的时间戳丢给前端,后续查询都带时间戳重复上面的步骤。这个问题就是如果数据是实时更新的,除非回到第一页,不然出不来最新的数据。当时我们的数据是冷数据所以可以这么玩。
数据量有些大呢 ,现在是初期阶段,数据就有几百条了
分表是业务需求,当时也是第一次用mongodb,压根没想到分表聚合查询问题这么大
我再试试,不行的话,我就反馈上去了,唉真麻烦
这个好像可以,但是。。这样不能跳页了
我不知道甲方会不会满意,真麻了
一般需要准确分页的场景也不多。
可以支持按照时间点跳。 预设日期 或者小时 类似于日志系统。
大不了历史数据 按照时间点,统计好条数放那参考。
这个场景好像之前遇到过,因为数据量非常大,我记得同事说最后的解决方法是把所有数据丢 ES里面 放弃了mongo 哈哈哈