许久没有再写博客,发生了很多事。最近在学习MongoDB,简单记录一下mongoDB的聚合语句:
db.alarm.aggregate([// {$match:{'$and': [{'event_status': {'$in': ['white', 'rejected']}}]}},// {$unwind: "$tag"}, //这里要特别注意不能够使用unwind{'$project': {'emergency_degree': 1, 'tag3': 1, 'business_id': 1, 'tag': 1, 'service_status': 1, 'event_status': 1, 'asset_type': 1, 'company_id': 1, 'source': 1, 'create_time': 1, 'latest_time': 1, 'asset': 1, '_id': {'$concat': ['$company_id', '-', '$asset']}}},// {'$match': {'$and': []}}, {'$group': {'emergency_degree': {'$max': '$emergency_degree'}, 'tags': {'$addToSet': '$tag'}, 'create_time': {'$min': '$create_time'}, 'certainty_levels': {'$addToSet': '$tag3'}, 'business_id': {'$min': '$business_id'}, 'company_id': {'$first': '$company_id'}, // 'alarm_ids': {'$addToSet': {'$cond': {'then': '$_id', 'else': '', 'if': {'$or': [{'$eq': ['$_id', 'inited']}, {'$eq': ['$_id', 'rejected']}]}}}},'alarm_ids':{'$addToSet':{'$cond':{'if':{ "$or": [{ "$eq": ["$event_status",'inited' ]}, { "$eq": ["$event_status", 'rejected']}]},'then':'$_id','else':''}}},'alarm_num': {'$sum': {'$cond': {'then': 1, 'else': 0, 'if': {'$eq': ['$event_status', 'inited']}}}}, 'latest_time': {'$max': '$latest_time'}, 'asset': {'$first': '$asset'}, 'event_status': {'$addToSet': '$event_status'}, 'service_status': {'$max': '$service_status'}, '_id': '$_id','tag3': {'$max': '$tag3'}, 'asset_type': {'$min': '$asset_type'},'source': {'$first': '$source'}}}, {'$match': {'tag3': 2}}, {'$sort': {'latest_time': -1}}],{'$skip':100},{'$limit':100},
{allowDiskUse:true
})
一些点与小坑记录如下
1、$unwind,在MongoDB中实现了类似于Python中flatten列表的功能,但是unwind之后会影响整个aggregate语句的count计数,原因暂时不清楚。
2、$cond,条件语句,本来想写一个满足条件就addToset,不满足条就continue。但是$cond这一个聚合操作符中似乎没有continue,于是将不满足的直接提取成空串。由于这个聚合语句是送到pymongo进行执行,后续可以利用Python本身的filter语句来进行后续处理。
3、$group中似乎没法保留原字段不变,如果需要保留一些字段的话需要使用$max,$first,$last,$min这样的操作符来保留字段。
4、不到特殊情况,不建议使用group来聚合,因为像上面这样的聚合语句;比一次find加上多次distinct要慢很多。
5、聚合常见的优化方式:
- group中要聚合的字段(即要展示为_id的字段)需要增加索引。
- group之前可以通过project来减少聚合的范围。
- sort字段需要增加索引
- group应该尽量与limit联合使用,提高查找效率。