Przeglądaj źródła

历史mongodb问题全部处理

z332406259 4 lat temu
rodzic
commit
ad3275596c

+ 3 - 3
app/extend/context.js

@@ -15,9 +15,6 @@ module.exports = {
   validate(rules = this.createCommonRule(), data) {
     data = data || this.query || this.request.body || {};
     console.log('参数', data);
-    if (data.startTime && data.endTime && data.startTime > data.endTime) {
-      this.throw(400, '开始时间不能小于结束时间');
-    }
     const errors = this.app.validator.validate(rules, data);
     if (errors) {
       this.throw(422, '参数校验失败', {
@@ -25,6 +22,9 @@ module.exports = {
         errors,
       });
     }
+    if (data.startTime && data.endTime && data.startTime > data.endTime) {
+      this.throw(400, '开始时间不能小于结束时间');
+    }
     this.logger.debug('参数', data);
     return data;
   },

+ 63 - 74
app/extend/helper.js

@@ -164,44 +164,7 @@ exports.getTimeRangMatch = (startTime, endTime, dateStr = 'create_date') => {
   return match;
 };
 
-// 获取活跃app的条件
-exports.getAppActiveCond = ({ startTime, endTime }) => {
-  return [
-    { $match: { ...this.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
-    { $sort: { login_time: 1 } },
-    { $group: {
-      _id: '$user_Id',
-      login_count: { $sum: 1 },
-      provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
-    } },
-    { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
-    { $project: {
-      login_count: 1,
-      area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-      provice_name: '$provice_name',
-      city_name: '$city_name',
-    } },
-    { $lookup:
-          {
-            from: 'app_behavior_record',
-            let: { user_id: '$_id' },
-            pipeline: [{ $match: { $expr: { $and:
-                      [
-                        { $eq: [ '$user_id', '$$user_id' ] },
-                        { $gte: [ '$create_time', startTime ] },
-                        { $lt: [ '$create_time', endTime ] },
-                      ] } } }], as: 'behaviors',
-          },
-    },
-    { $unwind: { path: '$behaviors', preserveNullAndEmptyArrays: true } },
-    { $group: {
-      _id: '$_id', login_count: { $first: '$login_count' },
-      use_duration: { $sum: { $cond: [ '$behaviors.use_duration', '$behaviors.use_duration', 0 ] } },
-      area_name: { $first: '$area_name' }, provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
-    } },
-    { $match: { $or: [{ use_duration: { $gt: 30 * 60 * 1000 } }, { login_count: { $gte: 3 } }] } },
-  ];
-};
+
 // 获取活跃car的条件
 exports.getCarActiveCond = ({ startTime, endTime }) => {
   return [
@@ -224,22 +187,29 @@ exports.getCarActiveCond = ({ startTime, endTime }) => {
       user_id: { $first: '$user_id' },
       series_code: { $first: '$series_code' }, model_code: { $first: '$model_code' },
     } },
-    { $lookup: {
-      from: 't-box_online_info',
-      let: { vin: '$_id' },
-      pipeline: [{ $match: { $expr: { $and:
-                [
-                  { $eq: [ '$vin', '$$vin' ] },
-                  { $gte: [ '$online_time', this.getMonthTop(startTime) ] },
-                  { $lt: [ '$online_time', endTime ] },
-                ] } } }], as: 'tbox',
-    } },
-    { $addFields: {
-      online_count: { $size: '$tbox' },
-    } },
   ];
 };
 
+
+// 获取区域分组语句  (之前的前置语句或者结果必须存在 元素属性:city_name,area_name,provice_name)
+exports.getLocationMongo = () => {
+  return [
+    { $group: { _id: { area_name: '$area_name', provice_name: '$provice_name', city_name: '$city_name' },
+      count: { $sum: 1 } } },
+    { $group: { _id: { area_name: '$_id.area_name', provice_name: '$_id.provice_name' },
+      cities: { $push: { city_name: '$_id.city_name', count: '$count' } },
+      count: { $sum: '$count' } } },
+    { $group: { _id: { area_name: '$_id.area_name' },
+      provinces: { $push: { provice_name: '$_id.provice_name', cities: '$cities', count: '$count' } },
+      count: { $sum: '$count' } } },
+    { $group: { _id: null,
+      areas: { $push: { area_name: '$_id.area_name', provinces: '$provinces', count: '$count' } },
+      count: { $sum: '$count' } } },
+  ];
+};
+
+
+
 // 获取年龄和性别分组语句  (之前的前置语句或者结果必须存在 元素属性: id_card,gender)
 exports.getAggAndSexMongo = () => {
   return [
@@ -268,30 +238,9 @@ exports.getAggAndSexMongo = () => {
   ];
 };
 
-// 获取区域分组语句  (之前的前置语句或者结果必须存在 元素属性:city_code,city_name,area_code,area_name,provice_code,provice_name)
-exports.getLocationMongo = () => {
-  return [
-    { $group: { _id: { city_code: '$city_code', city_name: '$city_name' },
-      area_code: { $first: '$area_code' }, area_name: { $first: '$area_name' },
-      provice_code: { $first: '$provice_code' }, provice_name: { $first: '$provice_name' },
-      count: { $sum: 1 } } },
-    { $group: { _id: { provice_code: '$provice_code', provice_name: '$provice_name' },
-      area_code: { $first: '$area_code' }, area_name: { $first: '$area_name' },
-      cities: { $push: { city_code: '$_id.city_code', city_name: '$_id.city_name', count: '$count' } },
-      count: { $sum: '$count' } } },
-    { $group: { _id: { area_code: '$area_code', area_name: '$area_name' },
-      provinces: { $push: { provice_code: '$_id.provice_code', provice_name: '$_id.provice_name',
-        cities: '$cities',
-        count: '$count' } },
-      count: { $sum: '$count' } } },
-    { $group: { _id: null,
-      areas: { $push: { area_code: '$_id.area_code', area_name: '$_id.area_name',
-        provinces: '$provinces',
-        count: '$count' } },
-      count: { $sum: '$count' } } },
-  ];
+exports.unionArray = (a, b) => {
+  return [ ...new Set([ ...a, ...b ]) ];
 };
-
 // 获取消息类型 时间分组语句
 exports.getMsgTimeGroupMongo = type => {
   switch (type) {
@@ -532,6 +481,7 @@ exports.getStatusInfoArr = () => {
   return arr;
 };
 
+
 // 弃用  来源唯一
 exports.statusInfo = [
   [
@@ -559,3 +509,42 @@ exports.statusInfo = [
   ],
 ];
 
+// 获取活跃app的条件
+exports.getAppActiveCond = ({ startTime, endTime }) => {
+  return [
+    { $match: { ...this.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
+    { $sort: { login_time: 1 } },
+    { $group: {
+        _id: '$user_Id',
+        login_count: { $sum: 1 },
+        provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
+      } },
+    { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
+    { $project: {
+        login_count: 1,
+        area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
+        provice_name: '$provice_name',
+        city_name: '$city_name',
+      } },
+    { $lookup:
+          {
+            from: 'app_behavior_record',
+            let: { user_id: '$_id' },
+            pipeline: [{ $match: { $expr: { $and:
+                      [
+                        { $eq: [ '$user_id', '$$user_id' ] },
+                        { $gte: [ '$create_time', startTime ] },
+                        { $lt: [ '$create_time', endTime ] },
+                      ] } } }], as: 'behaviors',
+          },
+    },
+    { $unwind: { path: '$behaviors', preserveNullAndEmptyArrays: true } },
+    { $group: {
+        _id: '$_id', login_count: { $first: '$login_count' },
+        use_duration: { $sum: { $cond: [ '$behaviors.use_duration', '$behaviors.use_duration', 0 ] } },
+        area_name: { $first: '$area_name' }, provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
+      } },
+    { $match: { $or: [{ use_duration: { $gt: 30 * 60 * 1000 } }, { login_count: { $gte: 3 } }] } },
+  ];
+};
+

+ 2 - 2
app/model/iviOnlineUserModel.js

@@ -11,7 +11,7 @@ module.exports = app => {
     user_mobileno: { type: String }, // 登录手机号
     vin: { type: String }, // vin
     role_id: { type: String },
-    // CAR_OWNER 是车主,user是使用人,POTENTIAL是潜客(粉丝)TODO 这边的角色和正常的不一样
+    // owner 是车主,common是使用人,guest是潜客(粉丝)
     login_time: { type: Number }, // 登录时间戳
     longitude: { type: Number }, // 登录位置-经度  TODO 无
     latitude: { type: Number }, // 登录位置-纬度
@@ -25,7 +25,7 @@ module.exports = app => {
     county_name: { type: String }, // 登录位置-行政区名称 TODO 无
     // series_code: { type: String }, // 车系编码
     // series_name: { type: String }, // 车系名称
-    login_mode: { type: String }, // 登录方式 (1:人脸、2:声纹、3:密码、4:验证码、5:二维码)
+    login_mode: { type: Number }, // 登录方式 (1:人脸、2:声纹、3:密码、4:验证码、5:二维码)
     // FACE/SOUND/PASSWORD/VERIFICATION_CODE/QR
     login_state: { type: Number }, // 登录状态 (1:成功、2:失败) TODO 无
   });

+ 4 - 4
app/schedule/updateData.js

@@ -9,7 +9,7 @@ class UpdateData extends Subscription {
       // interval: '24h', // 1 分钟间隔
       cron: '0 30 3 * * ? ', // 每天凌晨3点
       type: 'worker', //  all 指定所有的都需要执行  worker 其中一个
-      immediate: true,
+      // immediate: true,
       cronOptions: {
         tz: 'Asia/Shanghai',
       },
@@ -22,7 +22,7 @@ class UpdateData extends Subscription {
     // const result = await this.app.getHistoryModel('2006').find({}).limit(10);
     // this.app.logger.info(result);
     // await this.doTask();
-    await this.roundTask();
+    // await this.roundTask();
     await this.endTask();
   }
 
@@ -55,7 +55,7 @@ class UpdateData extends Subscription {
     this.isRunningTask = true;
 
     // 更新历史时间段数据 => 修改createBaseData的参数做循环请求即可
-    const satrtMoment = this.ctx.helper.momentDate('2020-01-01');
+    const satrtMoment = this.ctx.helper.momentDate('2020-05-01');
 
     // const satrtMoment = this.ctx.helper.momentDate('2020-06-01');
     // const endTime = this.ctx.helper.parse('2019-06-17');
@@ -70,7 +70,7 @@ class UpdateData extends Subscription {
       // await this.ctx.service.onlineUserService2.statistics(this.createBaseData(startTime, eTime));
       // await this.ctx.service.drivingBehaviorInfoService2.statistics(this.createBaseData(startTime, eTime));
       // await this.ctx.service.statsBaseInfoService2.statistics(this.createBaseData(startTime, eTime));
-      await this.ctx.service.tVehicleRecordService2.statistics(this.createBaseData(startTime, eTime));
+      // await this.ctx.service.tVehicleRecordService2.statistics(this.createBaseData(startTime, eTime));
       // await this.ctx.service.tVehicleReportInfoService.statistics(this.createBaseData(startTime, eTime));
       //
       // await this.ctx.service.appBehaviorRecordService.statistics(this.createBaseData(startTime, eTime));

+ 9 - 5
app/service/appBehaviorRecordService.js

@@ -165,8 +165,10 @@ class AppBehaviorRecordService extends Service {
   async remoteControl({ startTime, endTime }) {
     const { ctx } = this;
     const agg = [
-      { $match: { parent_behavior_id: ctx.helper.rcBehaviorId,
-        ...ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time') } },
+      { $match: {
+        ...ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time'),
+        parent_behavior_id: ctx.helper.rcBehaviorId,
+      } },
       {
         $group: {
           _id: { behavior_id: '$behavior_id', op: '$op', opType: '$op_type', closeType: '$closeType',
@@ -181,10 +183,12 @@ class AppBehaviorRecordService extends Service {
   async remoteControlFailure({ startTime, endTime }) {
     const { ctx } = this;
     const agg = [
-      { $match: { parent_behavior_id: ctx.helper.rcBehaviorId,
+      { $match: {
+        ...ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time'),
+        parent_behavior_id: ctx.helper.rcBehaviorId,
+        rc_execution_result: ctx.helper.rcResult.FAILED,
         rc_fail_type: { $exists: true },
-        rc_execution_result: { $in: [ 'false', 'FAILED' ] },
-        ...ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time') } },
+      } },
       {
         $group: {
           _id: '$rc_fail_type',

+ 1 - 1
app/service/dictService.js

@@ -45,7 +45,7 @@ class DictService extends Service {
     const { ctx } = this;
     const agg = [
       { $match: { parent_behavior_id: ctx.helper.rcBehaviorId,
-        rc_execution_result: { $in: [ 'false', 'FAILED' ] } } },
+        rc_execution_result: ctx.helper.rcResult.FAILED } },
       { $group: { _id: '$rc_fail_type' } },
       { $match: { _id: { $ne: null } } },
       { $project: { _id: 0, name: '$_id' } },

+ 2 - 5
app/service/drivingBehaviorInfoService2.js

@@ -300,10 +300,6 @@ class DrivingBehaviorInfoService2 extends Service {
     return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregate(agg);
   }
 
-  async ext() {
-
-  }
-
   // 统计清洗
   async statistics({ timeRangData, initData, isForceUpdate }) {
     const { ctx } = this;
@@ -314,7 +310,8 @@ class DrivingBehaviorInfoService2 extends Service {
     }
     initData.start_time = new Date();
 
-    const dHour = { $add: [{ $multiply: [{ $hour: { $toDate: '$$this.start_time' } }, 60 ] }, { $minute: { $toDate: '$$this.start_time' } }] };
+    const dHour = { $add: [{ $multiply: [{ $hour: { $toDate: '$$this.start_time' } }, 60 ] },
+      { $minute: { $toDate: '$$this.start_time' } }] };
 
     const mileageCnt = await this.bucketGroup(timeRangData,
       { $toDouble: '$mileage_cnt' }, [ 0, 30, 60, 90, 120, 10 * 10000 ]);

+ 184 - 229
app/service/onlineUserService2.js

@@ -141,63 +141,16 @@ class OnlineUserService2 extends Service {
       return;
     }
     initData.start_time = new Date();
-    let appTotal = 0;
-    let appPlace = [];
-    let tBoxTotal = 0;
-    let tBoxPlace = [];
-    let faceTotal = 0;
-    let voiceTotal = 0;
-    let pwdTotal = 0;
-    let codeTotal = 0;
-    let scanTotal = 0;
-    ctx.logger.info("1");
-    const iviTotal = await this.iviTotal(timeRangData);
-    let carTotal = 0;
-    let commonTotal = 0;
-    let guestTotal = 0;
+
+    const { appTotal, iviTotal, tBoxTotal } = await this.count(timeRangData);
+    const total = appTotal + tBoxTotal;
+
+    const { faceTotal, voiceTotal, pwdTotal, codeTotal, scanTotal } = await this.modeGroup(timeRangData);
+
+    const { carTotal, commonTotal, guestTotal } = await this.roleGroup(timeRangData);
+
     let successTotal = 0;
     let failTotal = 0;
-    ctx.logger.info("2");
-    const modes = await this.modeGroup(timeRangData);
-    modes.forEach(item => {
-      switch (item._id) { // 1:人脸、2:声纹、3:密码、4:验证码、5:二维码
-        case 'FACE':
-          faceTotal += item.count;
-          break;
-        case 'SOUND':
-          voiceTotal += item.count;
-          break;
-        case 'PASSWORD':
-          pwdTotal += item.count;
-          break;
-        case 'VERIFICATION_CODE':
-          codeTotal += item.count;
-          break;
-        case 'QR':
-          scanTotal += item.count;
-          break;
-        default:
-          break;
-      }
-    });
-    ctx.logger.info("3");
-    const roles = await this.roleGroup(timeRangData);
-    roles.forEach(item => {
-      switch (item._id) {
-        case 'CAR_OWNER':
-          carTotal += item.count;
-          break;
-        case 'user':
-          commonTotal += item.count;
-          break;
-        case 'POTENTIAL':
-          guestTotal += item.count;
-          break;
-        default:
-          break;
-      }
-    });
-    ctx.logger.info("4");
     const status = await this.statusGroup(timeRangData);
     status.forEach(item => {
       switch (item._id) {
@@ -211,20 +164,18 @@ class OnlineUserService2 extends Service {
           break;
       }
     });
-    ctx.logger.info("5");
+
+    let appPlace = [];
+    let tBoxPlace = [];
     const aResult = await this.appPlace(ctx.helper.getTimeRangMatch(
       timeRangData.startTime, timeRangData.endTime, 'login_time'));
     if (aResult && aResult.length > 0) {
-      appTotal = aResult[0].count;
       appPlace = aResult[0].areas;
     }
-    ctx.logger.info("6");
     const tResult = await this.tBoxPlace(timeRangData);
     if (tResult && tResult.length > 0) {
-      tBoxTotal = tResult[0].count;
       tBoxPlace = tResult[0].areas;
     }
-    const total = appTotal + tBoxTotal;
 
     let appLocation = [];
     let appNewLocation = [];
@@ -232,36 +183,30 @@ class OnlineUserService2 extends Service {
     let iviLocation = [];
     let iviNewLocation = [];
     let iviActiveLocation = [];
-    ctx.logger.info("7");
     const al = await this.appPlace({ login_time: { $lt: timeRangData.endTime } });
     if (al && al.length > 0) {
       appLocation = al[0].areas;
     }
-    ctx.logger.info("8");
-    // const anl = await this.appNewLocation(timeRangData);TODO 问题
-    // if (anl && anl.length > 0) {
-    //   appNewLocation = anl[0].areas;
-    // }
-    ctx.logger.info("9");
-    // const aal = await this.appActiveLocation(timeRangData);TODO 问题
-    // if (aal && aal.length > 0) {
-    //   appActiveLocation = aal[0].areas;
-    // }
-    ctx.logger.info("10");
+    const anl = await this.appNewLocation(timeRangData);
+    if (anl && anl.length > 0) {
+      appNewLocation = anl[0].areas;
+    }
+    const aal = await this.appActiveLocation(timeRangData);
+    if (aal && aal.length > 0) {
+      appActiveLocation = aal[0].areas;
+    }
     const il = await this.iviLocation(timeRangData);
     if (il && il.length > 0) {
       iviLocation = il[0].areas;
     }
-    ctx.logger.info("11");
-    // const inl = await this.iviNewLocation(timeRangData);TODO 问题
-    // if (inl && inl.length > 0) {
-    //   iviNewLocation = inl[0].areas;
-    // }
-    ctx.logger.info("12");
-    // const ial = await this.iviActiveLocation(timeRangData);TODO 问题
-    // if (ial && ial.length > 0) {
-    //   iviActiveLocation = ial[0].areas;
-    // }
+    const inl = await this.iviNewLocation(timeRangData);
+    if (inl && inl.length > 0) {
+      iviNewLocation = inl[0].areas;
+    }
+    const ial = await this.iviActiveLocation(timeRangData);
+    if (ial && ial.length > 0) {
+      iviActiveLocation = ial[0].areas;
+    }
     initData.end_time = new Date();
 
     await ctx.service.statisticsService.save(ctx.model.Local.OnlineUserModel,
@@ -274,10 +219,20 @@ class OnlineUserService2 extends Service {
       }, isForceUpdate);
   }
 
-  async iviTotal({ startTime, endTime }) {
+  async count({ startTime, endTime }) {
     const { ctx } = this;
-    return await ctx.model.IviOnlineUserModel.find(
+    let iviTotal = 0;
+    let appTotal = 0;
+    let tBoxTotal = 0;
+    iviTotal = await ctx.model.IviOnlineUserModel.find(
       ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time')).countDocuments();
+    appTotal = await ctx.model.AppOnlineUserModel.find(
+      { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 })
+      .countDocuments();
+    tBoxTotal = await ctx.model.TBoxOnlineModel.find(
+      { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 })
+      .countDocuments();
+    return { appTotal, tBoxTotal, iviTotal };
   }
 
   async modeGroup({ startTime, endTime }) {
@@ -286,9 +241,56 @@ class OnlineUserService2 extends Service {
       { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time') },
       { $group: { _id: '$login_mode', count: { $sum: 1 } } },
     ];
+    let faceTotal = 0;
+    let voiceTotal = 0;
+    let pwdTotal = 0;
+    let codeTotal = 0;
+    let scanTotal = 0;
     const aResult = await ctx.model.AppOnlineUserModel.aggregate(agg);
+    aResult.forEach(item => {
+      switch (item._id) { // 1:人脸、2:声纹、3:密码、4:验证码、5:二维码
+        case 'FACE':
+          faceTotal += item.count;
+          break;
+        case 'SOUND':
+          voiceTotal += item.count;
+          break;
+        case 'PASSWORD':
+          pwdTotal += item.count;
+          break;
+        case 'VERIFICATION_CODE':
+          codeTotal += item.count;
+          break;
+        case 'QR':
+          scanTotal += item.count;
+          break;
+        default:
+          break;
+      }
+    });
     const iResult = await ctx.model.IviOnlineUserModel.aggregate(agg);
-    return aResult.concat(iResult);
+    iResult.forEach(item => {
+      switch (item._id) { // 1:人脸、2:声纹、3:密码、4:验证码、5:二维码
+        case 1:
+          faceTotal += item.count;
+          break;
+        case 2:
+          voiceTotal += item.count;
+          break;
+        case 3:
+          pwdTotal += item.count;
+          break;
+        case 4:
+          codeTotal += item.count;
+          break;
+        case 5:
+          scanTotal += item.count;
+          break;
+        default:
+          break;
+      }
+    });
+    return { faceTotal, voiceTotal, pwdTotal, codeTotal, scanTotal };
   }
 
   async roleGroup({ startTime, endTime }) {
@@ -297,9 +299,42 @@ class OnlineUserService2 extends Service {
       { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time') },
       { $group: { _id: '$role_id', count: { $sum: 1 } } },
     ];
+    let carTotal = 0;
+    let commonTotal = 0;
+    let guestTotal = 0;
     const aResult = await ctx.model.AppOnlineUserModel.aggregate(agg);
+    aResult.forEach(item => {
+      switch (item._id) {
+        case 'CAR_OWNER':
+          carTotal += item.count;
+          break;
+        case 'user':
+          commonTotal += item.count;
+          break;
+        case 'POTENTIAL':
+          guestTotal += item.count;
+          break;
+        default:
+          break;
+      }
+    });
     const iResult = await ctx.model.IviOnlineUserModel.aggregate(agg);
-    return aResult.concat(iResult);
+    iResult.forEach(item => { // owner 是车主,common是使用人,guest是潜客(粉丝)
+      switch (item._id) {
+        case 'owner':
+          carTotal += item.count;
+          break;
+        case 'common':
+          commonTotal += item.count;
+          break;
+        case 'guest':
+          guestTotal += item.count;
+          break;
+        default:
+          break;
+      }
+    });
+    return { carTotal, commonTotal, guestTotal };
   }
 
   async statusGroup({ startTime, endTime }) {
@@ -313,212 +348,135 @@ class OnlineUserService2 extends Service {
     return aResult.concat(iResult);
   }
 
-
   async appNewLocation(timeRangData) {
     const { ctx } = this;
+    const userArr = await ctx.model.TRbacUserModel.find({
+      create_date: { $gte: ctx.helper.getMonthTop(timeRangData.startTime), $lt: timeRangData.endTime },
+      user_orgin: 'APP' }, { user_id: 1, _id: 0 });
+
     const agg = [
-      { $match: { login_state: 1 } },
-      { $lookup: {
-        from: 't_rbac_user',
-        let: { user_id: '$user_Id' },
-        pipeline: [{ $match: { $expr: { $and:
-                    [
-                      { $eq: [ '$user_id', '$$user_id' ] },
-                      { $gte: [ '$create_date', ctx.helper.getMonthTop(timeRangData.startTime) ] },
-                      { $lt: [ '$create_date', timeRangData.endTime ] },
-                    ] } } }], as: 'user',
-      } },
-      { $unwind: '$user' },
+      { $match: { login_time: { $gte: ctx.helper.getMonthTop(timeRangData.startTime), $lt: timeRangData.endTime },
+        login_state: 1, user_Id: { $in: userArr.map(item => item.user_id) } } },
       { $sort: { login_time: 1 } },
       { $group: { _id: '$user_Id',
-        // area_code: { $first: '$area_code' }, area_name: { $first: '$area_name' },
-        // provice_code: { $first: '$provice_code' }, city_code: { $first: '$city_code' },
         provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
-      { $lookup: { from: 't_sync_province', localField: 'provice_name', foreignField: 'province_name', as: 'pro' } },
-      { $unwind: '$pro' },
-      { $lookup: {
-        from: 't_sync_city',
-        let: { city_name: '$city_name', province_id: '$pro.province_id' },
-        pipeline: [{ $match: { $expr: { $and:
-                  [
-                    { $eq: [ '$city_name', '$$city_name' ] },
-                    { $eq: [ '$province_id', '$$province_id' ] },
-                  ] } } }], as: 'city',
-      } },
-      { $unwind: '$city' },
       { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
       { $project: {
-        area_code: { $arrayElemAt: [ '$area.area_code', 0 ] },
         area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-        provice_code: '$pro.pro_code',
-        provice_name: '$pro.province_name',
-        city_code: '$city.city_code',
-        city_name: '$city.city_name',
+        provice_name: 1,
+        city_name: 1,
       } },
+      { $match: { area_name: { $exists: true } } },
       ...ctx.helper.getLocationMongo(),
     ];
     return await ctx.model.AppOnlineUserModel.aggregate(agg);
   }
-
-  async appActiveLocation({ startTime, endTime }) {
+  async iviNewLocation(timeRangData) {
     const { ctx } = this;
-    const agg = [
-      ...ctx.helper.getAppActiveCond({ startTime, endTime }),
-      ...ctx.helper.getLocationMongo(),
-    ];
-    return await ctx.model.AppOnlineUserModel.aggregate(agg);
-  }
+    const userArr = await ctx.model.TRbacUserModel.find({
+      create_date: { $gte: ctx.helper.getMonthTop(timeRangData.startTime), $lt: timeRangData.endTime },
+      user_orgin: 'IVI' }, { user_id: 1, _id: 0 });
 
-  async iviLocation({ endTime }) {
-    const { ctx } = this;
     const agg = [
-      { $match: { login_time: { $lt: endTime }, login_state: 1 } },
+      { $match: { login_time: { $gte: ctx.helper.getMonthTop(timeRangData.startTime), $lt: timeRangData.endTime },
+        login_state: 1, user_id: { $in: userArr.map(item => item.user_id) } } },
       { $sort: { login_time: 1 } },
       { $group: { _id: '$user_id',
-        county_code: { $first: '$county_code' }, county_name: { $first: '$county_name' },
         provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
-      { $lookup: {
-        from: 't_sync_county',
-        let: { county_code: '$county_code', county_name: '$county_name', provice_name: '$provice_name', city_name: '$city_name' },
-        pipeline: [{ $match: { $expr: { $and:
-                    [
-                      { $eq: [ '$out_county_code', '$$county_code' ] },
-                      { $eq: [ '$county_name', '$$county_name' ] },
-                      { $eq: [ '$province_name', '$$provice_name' ] },
-                      { $eq: [ '$city_name', '$$city_name' ] },
-                    ] } } }], as: 'location',
-      } },
-      { $unwind: '$location' },
+      { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
       { $project: {
-        city_code: '$out_city_code',
-        city_name: '$city_name',
-        area_code: '$location.area_code',
-        area_name: '$location.area_name',
-        provice_code: '$out_pro_code',
-        provice_name: '$provice_name',
+        area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
+        provice_name: 1,
+        city_name: 1,
       } },
+      { $match: { area_name: { $exists: true } } },
       ...ctx.helper.getLocationMongo(),
     ];
     return await ctx.model.IviOnlineUserModel.aggregate(agg);
   }
-
-  async iviNewLocation(timeRangData) {
+  async appActiveLocation({ startTime, endTime }) {
     const { ctx } = this;
+    const appAgg = [
+      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time') },
+      { $group: { _id: '$user_id', use_duration: { $sum: '$use_duration' } } },
+      { $match: { use_duration: { $gt: 30 * 60 * 1000 } } },
+    ];
+    const result2 = await ctx.model.AppBehaviorRecordModel.aggregate(appAgg);
     const agg = [
-      { $match: { login_state: 1 } },
-      { $lookup: {
-        from: 't_rbac_user',
-        let: { user_id: '$user_id' },
-        pipeline: [{ $match: { $expr: { $and:
-                    [
-                      { $eq: [ '$user_id', '$$user_id' ] },
-                      { $gte: [ '$create_date', ctx.helper.getMonthTop(timeRangData.startTime) ] },
-                      { $lt: [ '$create_date', timeRangData.endTime ] },
-                    ] } } }], as: 'user',
-      } },
-      { $unwind: '$user' },
-      { $sort: { login_time: 1 } },
-      { $group: { _id: '$user_id',
-        county_code: { $first: '$county_code' }, county_name: { $first: '$county_name' },
-        provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
-      { $lookup: {
-        from: 't_sync_county',
-        let: { county_code: '$county_code', county_name: '$county_name', provice_name: '$provice_name', city_name: '$city_name' },
-        pipeline: [{ $match: { $expr: { $and:
-                    [
-                      { $eq: [ '$out_county_code', '$$county_code' ] },
-                      { $eq: [ '$county_name', '$$county_name' ] },
-                      { $eq: [ '$province_name', '$$provice_name' ] },
-                      { $eq: [ '$city_name', '$$city_name' ] },
-                    ] } } }], as: 'location',
+      { $match: { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
+      { $group: {
+        _id: '$user_Id', provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' },
+        login_count: { $sum: 1 },
       } },
-      { $unwind: '$location' },
+      { $match: { $or: [{ _id: { $in: result2.map(item => item._id) } }, { login_count: { $gte: 3 } }] } },
+      { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
       { $project: {
-        city_code: '$out_city_code',
-        city_name: '$city_name',
-        area_code: '$location.area_code',
-        area_name: '$location.area_name',
-        provice_code: '$out_pro_code',
-        provice_name: '$provice_name',
+        area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
+        provice_name: 1,
+        city_name: 1,
       } },
+      { $match: { area_name: { $exists: true } } },
       ...ctx.helper.getLocationMongo(),
     ];
-    return await ctx.model.IviOnlineUserModel.aggregate(agg);
-  }
 
+    return await ctx.model.AppOnlineUserModel.aggregate(agg);
+  }
   async iviActiveLocation({ startTime, endTime }) {
     const { ctx } = this;
     const agg = [
       { $match: { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
       { $sort: { login_time: 1 } },
+      { $group: { _id: '$user_id', provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
+      { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
+      { $project: {
+        area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
+        provice_name: 1,
+        city_name: 1,
+      } },
+      ...ctx.helper.getLocationMongo(),
+    ];
+    return await ctx.model.IviOnlineUserModel.aggregate(agg);
+  }
+  async iviLocation({ endTime }) {
+    const { ctx } = this;
+    const agg = [
+      { $match: { login_time: { $lt: endTime }, login_state: 1 } },
+      { $sort: { login_time: 1 } },
       { $group: { _id: '$user_id',
-        county_code: { $first: '$county_code' }, county_name: { $first: '$county_name' },
         provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
-      { $lookup: {
-        from: 't_sync_county',
-        let: { county_code: '$county_code', county_name: '$county_name', provice_name: '$provice_name', city_name: '$city_name' },
-        pipeline: [{ $match: { $expr: { $and:
-                    [
-                      { $eq: [ '$out_county_code', '$$county_code' ] },
-                      { $eq: [ '$county_name', '$$county_name' ] },
-                      { $eq: [ '$province_name', '$$provice_name' ] },
-                      { $eq: [ '$city_name', '$$city_name' ] },
-                    ] } } }], as: 'location',
-      } },
-      { $unwind: '$location' },
+      { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
       { $project: {
-        city_code: '$out_city_code',
-        city_name: '$city_name',
-        area_code: '$location.area_code',
-        area_name: '$location.area_name',
-        provice_code: '$out_pro_code',
-        provice_name: '$provice_name',
+        area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
+        provice_name: 1,
+        city_name: 1,
       } },
+      { $match: { area_name: { $exists: true } } },
       ...ctx.helper.getLocationMongo(),
     ];
     return await ctx.model.IviOnlineUserModel.aggregate(agg);
   }
-
   async appPlace(cond) {
     const { ctx } = this;
     const agg = [
       { $match: { ...cond, login_state: 1 } },
       { $sort: { login_time: 1 } },
       { $group: { _id: '$user_Id',
-        /* area_code: { $first: '$area_code' }, area_name: { $first: '$area_name' },
-        provice_code: { $first: '$provice_code' },city_code: { $first: '$city_code' },*/
         provice_name: { $first: '$provice_name' }, city_name: { $first: '$city_name' } } },
-      { $lookup: { from: 't_sync_province', localField: 'provice_name', foreignField: 'province_name', as: 'pro' } },
-      { $unwind: '$pro' },
-      { $lookup: {
-        from: 't_sync_city',
-        let: { city_name: '$city_name', province_id: '$pro.province_id' },
-        pipeline: [{ $match: { $expr: { $and:
-                  [
-                    { $eq: [ '$city_name', '$$city_name' ] },
-                    { $eq: [ '$province_id', '$$province_id' ] },
-                  ] } } }], as: 'city',
-      } },
-      { $unwind: '$city' },
       { $lookup: { from: 't_sync_county', localField: 'provice_name', foreignField: 'province_name', as: 'area' } },
       { $project: {
-        area_code: { $arrayElemAt: [ '$area.area_code', 0 ] },
         area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-        provice_code: '$pro.pro_code',
-        provice_name: '$pro.province_name',
-        city_code: '$city.city_code',
-        city_name: '$city.city_name',
+        provice_name: 1,
+        city_name: 1,
       } },
+      { $match: { area_name: { $exists: true } } },
       ...ctx.helper.getLocationMongo(),
     ];
     return await ctx.model.AppOnlineUserModel.aggregate(agg);
   }
-
   async tBoxPlace({ startTime, endTime }) {
     const { ctx } = this;
     const agg = [
       { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'online_time') },
-      { $sort: { online_time: 1 } },
       { $group: { _id: '$vin' } },
       { $lookup: { from: 't_vehicle_record', localField: '_id', foreignField: 'vin', as: 'car' } },
       { $unwind: '$car' },
@@ -536,11 +494,8 @@ class OnlineUserService2 extends Service {
       { $unwind: '$city' },
       { $lookup: { from: 't_sync_county', localField: 'car.pro_code', foreignField: 'out_pro_code', as: 'area' } },
       { $project: {
-        area_code: { $arrayElemAt: [ '$area.area_code', 0 ] },
         area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-        provice_code: '$car.pro_code',
         provice_name: '$pro.province_name',
-        city_code: '$car.city_code',
         city_name: '$city.city_name',
       } },
       ...ctx.helper.getLocationMongo(),

+ 64 - 45
app/service/tRbacUserService.js

@@ -38,25 +38,26 @@ class TRbacUserService extends Service {
     initData.start_time = new Date();
     const total = await this.total({ create_date: { $lt: timeRangData.endTime } });
     const sexAndAgeTotal = await this.sex2Age({ create_date: { $lt: timeRangData.endTime } });
-    const appTotal = await this.total({ user_orgin: 'APP', create_date: { $lt: timeRangData.endTime } });
-    const appSexAndAgeTotal = await this.sex2Age({ user_orgin: 'APP', create_date: { $lt: timeRangData.endTime } });
-    const iviTotal = await this.total({ user_orgin: 'IVI', create_date: { $lt: timeRangData.endTime } });
-    const iviSexAndAgeTotal = await this.sex2Age({ user_orgin: 'IVI', create_date: { $lt: timeRangData.endTime } });
-    const newAppTotal = await this.total({ user_orgin: 'APP',
-      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime } });
-    const newAppSexAndAgeTotal = await this.sex2Age({ user_orgin: 'APP',
-      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime } });
-    const newIviTotal = await this.total({ user_orgin: 'IVI',
-      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime } });
-    const newIviSexAndAgeTotal = await this.sex2Age({ user_orgin: 'IVI',
-      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime } });
-    const activeAppTotal = await this.activeAppTotal(timeRangData); //TODO 问题
-    // const activeAppTotal = 0;
-    const activeAppSexAndAgeTotal = await this.activeAppSex2Age(timeRangData); //TODO 问题
-    // const activeAppSexAndAgeTotal = [];
+    const appTotal = await this.total({
+      create_date: { $lt: timeRangData.endTime }, user_orgin: 'APP' });
+    const appSexAndAgeTotal = await this.sex2Age({
+      create_date: { $lt: timeRangData.endTime }, user_orgin: 'APP' });
+    const iviTotal = await this.total({
+      create_date: { $lt: timeRangData.endTime }, user_orgin: 'IVI' });
+    const iviSexAndAgeTotal = await this.sex2Age({
+      create_date: { $lt: timeRangData.endTime }, user_orgin: 'IVI' });
+    const newAppTotal = await this.total({
+      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime }, user_orgin: 'APP' });
+    const newAppSexAndAgeTotal = await this.sex2Age({
+      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime }, user_orgin: 'APP' });
+    const newIviTotal = await this.total({
+      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime, user_orgin: 'IVI' } });
+    const newIviSexAndAgeTotal = await this.sex2Age({
+      create_date: { $gte: timeRangData.startTime, $lt: timeRangData.endTime }, user_orgin: 'IVI' });
+    const activeAppTotal = await this.activeAppTotal(timeRangData);
+    const activeAppSexAndAgeTotal = await this.activeAppSex2Age(timeRangData);
     const activeIviTotal = await this.activeIviTotal(timeRangData);
     const activeIviSexAndAgeTotal = await this.activeIviSex2Age(timeRangData);
-
     initData.end_time = new Date();
     await ctx.service.statisticsService.save(ctx.model.Local.TRbacUserModel,
       { ...initData, total, sexAndAgeTotal,
@@ -77,7 +78,7 @@ class TRbacUserService extends Service {
   async sex2Age(cond) {
     const { ctx } = this;
     const agg = [
-      { $match: { role_id: ctx.helper.saledRoleId, ...cond } },
+      { $match: { ...cond, role_id: ctx.helper.saledRoleId } },
       ...ctx.helper.getAggAndSexMongo(),
     ];
     return await ctx.model.TRbacUserModel.aggregate(agg);
@@ -85,36 +86,56 @@ class TRbacUserService extends Service {
 
   async activeAppTotal({ startTime, endTime }) {
     const { ctx } = this;
-    const agg = [
-      ...ctx.helper.getAppActiveCond({ startTime, endTime }),
-      { $count: 'count' },
+    const onlineAgg = [
+      { $match: { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
+      { $group: {
+        _id: '$user_Id',
+        login_count: { $sum: 1 },
+      } },
+      { $match: { login_count: { $gte: 3 } } },
     ];
-    const result = await ctx.model.AppOnlineUserModel.aggregate(agg);
-    if (result && result.length > 0) {
-      return result[0].count;
-    }
-    return 0;
+    const appAgg = [
+      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time') },
+      { $group: { _id: '$user_id', use_duration: { $sum: '$use_duration' } } },
+      { $match: { use_duration: { $gt: 30 * 60 * 1000 } } },
+    ];
+    const result1 = await ctx.model.AppOnlineUserModel.aggregate(onlineAgg);
+    const result2 = await ctx.model.AppBehaviorRecordModel.aggregate(appAgg);
+    const map1 = result1.map(item => item._id);
+    const map2 = result2.map(item => item._id);
+    const unionArray = ctx.helper.unionArray(map1, map2);
+    return unionArray.length;
   }
 
   async activeAppSex2Age({ startTime, endTime }) {
     const { ctx } = this;
+    const onlineAgg = [
+      { $match: { ...ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 } },
+      { $group: {
+        _id: '$user_Id',
+        login_count: { $sum: 1 },
+      } },
+      { $match: { login_count: { $gte: 3 } } },
+    ];
+    const appAgg = [
+      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'create_time') },
+      { $group: { _id: '$user_id', use_duration: { $sum: '$use_duration' } } },
+      { $match: { use_duration: { $gt: 30 * 60 * 1000 } } },
+    ];
+    const result1 = await ctx.model.AppOnlineUserModel.aggregate(onlineAgg);
+    const result2 = await ctx.model.AppBehaviorRecordModel.aggregate(appAgg);
+    const unionArray = ctx.helper.unionArray(result1.map(item => item._id), result2.map(item => item._id));
     const agg = [
-      ...ctx.helper.getAppActiveCond({ startTime, endTime }),
-      { $lookup: { from: 't_rbac_user', localField: '_id', foreignField: 'user_id', as: 'user' } },
-      { $unwind: '$user' },
-      { $project: {
-        id_card: '$user.id_card',
-        gender: '$user.gender' },
-      },
+      { $match: { user_id: { $in: unionArray } } },
       ...ctx.helper.getAggAndSexMongo(),
     ];
-    return await ctx.model.AppOnlineUserModel.aggregate(agg);
+    return await ctx.model.TRbacUserModel.aggregate(agg);
   }
 
   async activeIviTotal({ startTime, endTime }) {
     const { ctx } = this;
     const agg = [
-      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time') },
+      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 },
       { $group: {
         _id: '$user_id' },
       },
@@ -129,21 +150,19 @@ class TRbacUserService extends Service {
 
   async activeIviSex2Age({ startTime, endTime }) {
     const { ctx } = this;
-    const agg = [
-      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time') },
+    const onlineAgg = [
+      { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'login_time'), login_state: 1 },
       { $group: {
         _id: '$user_id',
       } },
-      { $lookup: { from: 't_rbac_user', localField: '_id', foreignField: 'user_id', as: 'user' } },
-      { $unwind: '$user' },
-      { $project: {
-        id_card: '$user.id_card',
-        gender: '$user.gender',
-      },
-      },
+    ];
+    const result = await ctx.model.IviOnlineUserModel.aggregate(onlineAgg);
+    const unionArray = result.map(item => item._id);
+    const agg = [
+      { $match: { user_id: { $in: unionArray } } },
       ...ctx.helper.getAggAndSexMongo(),
     ];
-    return await ctx.model.IviOnlineUserModel.aggregate(agg);
+    return await ctx.model.TRbacUserModel.aggregate(agg);
   }
 
 }

+ 4 - 4
app/service/tRegisterInfoService.js

@@ -38,9 +38,9 @@ class TRegisterInfoService extends Service {
     const saledTotal = await ctx.model.TRbacUserModel.find(
       { role_id: ctx.helper.saledRoleId }).countDocuments();
     const saledAppTotal = await ctx.model.TRbacUserModel.find(
-      { role_id: ctx.helper.saledRoleId, user_orgin: 'APP' }).countDocuments();
+      { user_orgin: 'APP', role_id: ctx.helper.saledRoleId }).countDocuments();
     const saledIviTotal = await ctx.model.TRbacUserModel.find(
-      { role_id: ctx.helper.saledRoleId, user_orgin: 'IVI' }).countDocuments();
+      { user_orgin: 'IVI', role_id: ctx.helper.saledRoleId }).countDocuments();
     return { maxDay, maxMonth, saledTotal, saledAppTotal, saledIviTotal };
 
   }
@@ -56,9 +56,9 @@ class TRegisterInfoService extends Service {
       return;
     }
     initData.start_time = new Date();
-    const total = await this.total(ctx.helper.getTimeRangMatch(timeRangData.startTime,
+    const total = await this.count(ctx.helper.getTimeRangMatch(timeRangData.startTime,
       timeRangData.endTime, 'update_time'));
-    const saledTotal = await this.total({ update_time: { $lt: timeRangData.endTime } });
+    const saledTotal = await this.count({ update_time: { $lt: timeRangData.endTime } });
     initData.end_time = new Date();
 
     await ctx.service.statisticsService.save(ctx.model.Local.TRegisterInfoModel,

+ 69 - 25
app/service/tVehicleRecordService2.js

@@ -49,19 +49,14 @@ class TVehicleRecordService2 extends Service {
       { $lookup: { from: 't_sync_county', localField: '_id', foreignField: 'out_pro_code', as: 'area' } },
       { $project: {
         count: 1,
-        area_code: { $arrayElemAt: [ '$area.area_code', 0 ] },
         area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-        provice_code: '$pro.out_pro_code',
         provice_name: '$pro.province_name',
       } },
-      { $group: { _id: { area_code: '$area_code', area_name: '$area_name' },
-        provinces: { $push: { provice_code: '$provice_code', provice_name: '$provice_name',
-          count: '$count' } },
+      { $group: { _id: { area_name: '$area_name' },
+        provinces: { $push: { provice_name: '$provice_name', count: '$count' } },
         count: { $sum: '$count' } } },
       { $group: { _id: null,
-        areas: { $push: { area_code: '$_id.area_code', area_name: '$_id.area_name',
-          provinces: '$provinces',
-          count: '$count' } },
+        areas: { $push: { area_name: '$_id.area_name', provinces: '$provinces', count: '$count' } },
         count: { $sum: '$count' } } },
     ];
 
@@ -101,9 +96,7 @@ class TVehicleRecordService2 extends Service {
       { $project: {
         _id: 0,
         count: 1,
-        provice_code: '$pro_code',
         provice_name: '$pro.province_name',
-        city_code: '$city_code',
         city_name: '$city.city_name',
       } },
     ];
@@ -114,17 +107,36 @@ class TVehicleRecordService2 extends Service {
   // TODO 暂时即时查询
   async activeLocation({ startTime, endTime, seriesCode, modelCode }) {
     const { ctx } = this;
-    const cond = [{ $match: { } }];
+    const onlineAgg = [
+      { $match: { ...ctx.helper.getTimeRangMatch(ctx.helper.getMonthTop(startTime), endTime,
+        'online_time') } },
+      { $group: {
+        _id: '$vin',
+        login_count: { $sum: 1 },
+      } },
+      { $match: { login_count: { $gt: 3 } } },
+    ];
+    const driveAgg = [
+      { $match: ctx.helper.getTimeRangMatch(ctx.helper.getMonthTop(startTime), endTime,
+        'start_time') },
+      { $group: { _id: '$vin',
+        mileage: { $sum: { $cond: [ '$mileage', { $toDouble: '$mileage' }, 0 ] } } } },
+      { $match: { mileage: { $gt: 50 } } },
+    ];
+    const result1 = await ctx.model.TBoxOnlineModel.aggregate(onlineAgg);
+    const result2 = await ctx.model.DrivingBehaviorInfoModel.aggregate(driveAgg);
+    const unionArray = ctx.helper.unionArray(result1.map(item => item._id), result2.map(item => item._id));
+
+    const cond = { };
     if (seriesCode) {
-      cond[0].$match.series_code = seriesCode;
+      cond.series_code = seriesCode;
     }
 
     if (modelCode) {
-      cond[0].$match.model_code = modelCode;
+      cond.model_code = modelCode;
     }
     const agg = [
-      ...ctx.helper.getCarActiveCond({ startTime, endTime }),
-      { $match: { $or: [{ online_count: { $gt: 3 } }, { mileage: { $gt: 50 } }] } },
+      { $match: { vin: { $in: unionArray }, ...cond } },
       { $lookup: { from: 't_sync_province', localField: 'pro_code', foreignField: 'out_pro_code', as: 'pro' } },
       { $unwind: '$pro' },
       { $lookup: {
@@ -139,11 +151,8 @@ class TVehicleRecordService2 extends Service {
       { $unwind: '$city' },
       { $lookup: { from: 't_sync_county', localField: 'pro_code', foreignField: 'out_pro_code', as: 'area' } },
       { $project: {
-        area_code: { $arrayElemAt: [ '$area.area_code', 0 ] },
         area_name: { $arrayElemAt: [ '$area.area_name', 0 ] },
-        provice_code: '$pro_code',
         provice_name: '$pro.province_name',
-        city_code: '$city_code',
         city_name: '$city.city_name',
       } },
       ...ctx.helper.getLocationMongo(),
@@ -242,15 +251,20 @@ class TVehicleRecordService2 extends Service {
       return;
     }
     initData.start_time = new Date();
-    const result = await this.group(timeRangData); // TODO 问题
+    const result = await this.group(timeRangData);
+    const aResult = await this.activeCount(timeRangData);
     let car = [];
     let total = 0;
     if (result && result.length > 0) {
       car = result[0].car;
       total = result[0].total;
     }
-
-    // 实销城市 (按照时间 + 车型车系来取前三名)
+    aResult.forEach(c => {
+      const obj = car.find(item => item._id.series_code == c._id.series_code && item._id.model_code == c._id.model_code);
+      if (obj) {
+        obj.activeCount = c.count;
+      }
+    });
 
     initData.end_time = new Date();
 
@@ -263,19 +277,49 @@ class TVehicleRecordService2 extends Service {
     const { ctx } = this;
     const agg = [
       { $match: { create_time: { $lt: timeRangData.endTime } } },
-      // ...ctx.helper.getCarActiveCond(timeRangData),
       { $group: { _id: { series_code: '$series_code', model_code: '$model_code' },
-        count: { $sum: 1 }, saledCount: { $sum: {
+        count: { $sum: 1 },
+        saledCount: { $sum: {
           $cond: [{ $and: [{ $eq: [ '$is_saled_car', 1 ] }, { $ne: [ '$user_id', null ] },
             { $lt: [ '$sale_date', timeRangData.endTime ] }] }, 1, 0 ],
         } },
-        // activeCount: { $sum: { $cond: [
-        // { $or: [{ $gt: [ '$online_count', 3 ] }, { $gt: [ '$mileage', 50 ] }] }, 1, 0 ] } },
       } },
       { $group: { _id: null, car: { $push: '$$ROOT' }, total: { $sum: 'count' } } },
     ];
     return await ctx.model.TVehicleRecordModel.aggregate(agg);
   }
+
+  async activeCount(timeRangData) {
+    const { ctx } = this;
+    const onlineAgg = [
+      { $match: { ...ctx.helper.getTimeRangMatch(ctx.helper.getMonthTop(timeRangData.startTime), timeRangData.endTime,
+        'online_time') } },
+      { $group: {
+        _id: '$vin',
+        login_count: { $sum: 1 },
+      } },
+      { $match: { login_count: { $gt: 3 } } },
+    ];
+    const driveAgg = [
+      { $match: ctx.helper.getTimeRangMatch(ctx.helper.getMonthTop(timeRangData.startTime), timeRangData.endTime,
+        'start_time') },
+      { $group: { _id: '$vin',
+        mileage: { $sum: { $cond: [ '$mileage', { $toDouble: '$mileage' }, 0 ] } } } },
+      { $match: { mileage: { $gt: 50 } } },
+    ];
+    const result1 = await ctx.model.TBoxOnlineModel.aggregate(onlineAgg);
+    const result2 = await ctx.model.DrivingBehaviorInfoModel.aggregate(driveAgg);
+    const unionArray = ctx.helper.unionArray(result1.map(item => item._id), result2.map(item => item._id));
+
+    const agg = [
+      { $match: { vin: { $in: unionArray } } },
+      { $group: { _id: { series_code: '$series_code', model_code: '$model_code' },
+        count: { $sum: 1 },
+        // activeCount: { $sum: { $cond: [{ $in: [ '$vin', unionArray ] }, 1, 0 ] } },
+      } },
+    ];
+    return await ctx.model.TVehicleRecordModel.aggregate(agg);
+  }
 }
 
 module.exports = TVehicleRecordService2;