最近使用mongo时遇到一个问题,场景是:使用聚合 aggregate 函数,分页查找一张日志表。
一. 初始
查找规则是按照创建时间字段降序,并按照其中一个字段分组,然后通过skip、limit,实现分页的效果。
示例sql如下:
db.collection1
.aggregate([
{ "$match" : { "filed1" : "value1"}},
{ "$sort" : { "createTime" : -1}},
{ "$group" : { "_id" : "$field2"}},
{ "$skip" : 0},
{ "$limit" : 20}
]
);
结果发现有以下几个问题:
1.实际查找的顺序并不是从(整表)后向前,而是从前向后。即顺序和指定的createTime顺序相反;
2.返回的每页数据实际存在乱序和丢失的情况。即返回的一页 field2 并不是准确的这一页数据包含的field2,顺序也不对。
二. 第一次修改
怀疑是先sort再group会打乱顺序,于是将sort放在group之后执行。
示例:
db.collection1
.aggregate([
{ "$match" : { "filed1" : "value1"}},
{ "$group" : { "_id" : "$field2"}},
{ "$sort" : { "createTime" : -1}},
{ "$skip" : 0},
{ "$limit" : 20}
]
);
结果发现返回的顺序仍是乱掉的。
通过查看返回结果,发现实际只返回了分组的field2这一列属性,不包含排序的createTime字段,所以猜测排序实际没有意义。
三. 第二次修改:
分组时,返回每组第一条数据的createTime。
示例:
db.collection1
.aggregate([
{ "$match" : { "filed1" : "value1"}},
{ "$group" : { "_id" : "$field2", "createTime":{$first:"$createTime"}}},
{ "$sort" : { "createTime" : -1}},
{ "$skip" : 0},
{ "$limit" : 20}
]
);
然后再获取结果,果然符合预期了。
PS:
1.mongodb的资料很少,自己只能去官网看,而且一些使用细节也没有详细说明;
2.mongo 的 group 和 mysql 的 group 不一样,mysql 会返回select 指定的字段,且默认取第一条(一般按照主键id升序);mongo 聚合中使用group的话,默认只会返回 “_id” 对应的字段,其余字段需要显示设置获取规则,才会返回。
建议:
日志类数据还是老老实实用ES存吧,mongo并不适合