1、mongodb去重分页查询支持排序
原文地址
需求:查询一张表,根据某字段去重后返回指定信息,支持分页,排序。
逻辑:

1
2
3
4
5
1、match查询符合条件的数据
2、利用分组进行去重
3、返回全部字段信息
4、排序
5、分页

mongodb原生语句实现
返回指定字段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
db.getCollection('表名').aggregate([
{
    "$match" : {"failure":{$in:["具体失效文件"]}}    //
},
{  
     "$group" : { 
         "_id": { "lawId": "$lawId" },     //
         "id":{"$first" :"$_id"},              
         "lawId": {"$first" :"$lawId"},
         "date":{"$first" :"$date"}
    }
},
{ 
    "$project": {               //group基础上
        "_id": 1,
        "id":1,
        "lawId": 1,
        "date":1
    }
},
{"$sort": {"date":-1}},            //
{ "$skip":0 }, { "$limit":10 }     //
])

返回全部字段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
db.getCollection('表名').aggregate([
{
    "$match" : {"failure":{$in:["具体失效文件"]}}      //
},
{  
     "$group" : { 
         "_id": { "lawId": "$lawId" },     //
         "data":{"$first" :"$$ROOT"}      //
         }
},
{ 
    "$project": {
      "data":1,                         //
    }
},
{"$sort": {"data.dae":-1}},             //date.dae字段排序
{ "$skip":0 }, { "$limit":10 }          //
])

php的写法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 正常查询条件
$query = !empty($query) ? $query : new ArrayObject();
$pipe[] = ['$match' => $query];
// user_name 为去重的字段
$pipe[] = ['$group' => ['_id' => '$user_name', 'data' => ['$first' => '$$ROOT']]];
// 排序条件
$pipe[] = ['$sort' => $sort];
$pipe[] = ['$project' => ['data' => 1]];
// 分页参数
$pipe[] = ['$skip' => $index];
$pipe[] = ['$limit' => $count];
$docs = $this->mongoRead->aggregate($pipe, [], []);

2、去重求总数
原文地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
db.user_info.aggregate(
 {
   $group: {
     _id: '$user_name'
   }
 },
 {
   $group: {
     _id: 1,
     count: {
       $sum: 1
     }
   }
 }
)
1
2
3
4
5
$query = !empty($query) ? $query : new ArrayObject();
$pipe[] = ['$match' => $query];
$pipe[] = ['$group' => ['_id' => '$user_name']];
$pipe[] = ['$group' => ['_id' => 1, 'count' => ['$sum' => 1]]];
$ret = $this->mongoRead->aggregate($pipe);

3、批量插入测试数据

1
2
3
> for (var i = 0; i < 1000000; i++) {
... db.test.insert({"foo":"bar", "baz": i, "z" : 10 -i})
... }