drivingBehaviorInfoService2.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. 'use strict';
  2. const Service = require('egg').Service;
  3. class DrivingBehaviorInfoService2 extends Service {
  4. // 基本方法 计算匹配的时间段下 过滤车型车系后时间分组下 维度分布分组数据之和
  5. async index({ type, startTime, endTime, seriesCode, modelCode }, vString) {
  6. const { ctx } = this;
  7. const cond = [{ $match: {} }];
  8. if (seriesCode) {
  9. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  10. }
  11. if (modelCode) {
  12. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  13. }
  14. const agg = [
  15. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  16. { $unwind: `$${vString}` },
  17. ...cond,
  18. ...ctx.helper.getCarTimeGroupMongo(type, vString),
  19. ];
  20. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  21. }
  22. // 计算车辆出行和疲劳驾驶次数 两个维度count和dsmCount(类似index)
  23. async mileageStartTimeAndDsm({ type, startTime, endTime, seriesCode, modelCode }) {
  24. const { ctx } = this;
  25. const cond = [{ $match: {} }];
  26. if (seriesCode) {
  27. cond[0].$match['mileageStartTimeAndDsm._id.series_code'] = seriesCode;
  28. }
  29. if (modelCode) {
  30. cond[0].$match['mileageStartTimeAndDsm._id.model_code'] = modelCode;
  31. }
  32. const agg = [
  33. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  34. { $unwind: '$mileageStartTimeAndDsm' },
  35. ...cond,
  36. ...ctx.helper.getCarDSMTimeGroupMongo(type),
  37. ];
  38. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  39. }
  40. // 带有周末时间过滤(类似index)
  41. async date({ type, startTime, endTime, seriesCode, modelCode, week = 0 }, vString) {
  42. const { ctx } = this;
  43. const cond = [{ $match: {} }];
  44. const weekCond = [{ $match: {} }];
  45. const project = { $project: { year: 1, month: 1, day: 1,
  46. week: { $dayOfWeek: { date: { $toDate: '$create_date' }, timezone: 'Asia/Shanghai' } } } };
  47. project.$project[vString] = 1;
  48. if (seriesCode) {
  49. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  50. }
  51. if (modelCode) {
  52. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  53. }
  54. switch (week) {
  55. case 1:
  56. weekCond[0].$match.week = { $in: [ 2, 3, 4, 5, 6 ] };
  57. break;
  58. case 2:
  59. weekCond[0].$match.week = { $in: [ 1, 7 ] };
  60. break;
  61. default:
  62. break;
  63. }
  64. const agg = [
  65. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  66. project,
  67. ...weekCond,
  68. { $unwind: `$${vString}` },
  69. ...cond,
  70. ...ctx.helper.getCarTimeGroupMongo(type, vString),
  71. ];
  72. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  73. }
  74. // 求多个空调维度数据(无时间分组)
  75. async air({ startTime, endTime, seriesCode, modelCode }) {
  76. const { ctx } = this;
  77. const cond = [{ $match: {} }];
  78. if (seriesCode) {
  79. cond[0].$match['airAvg._id.series_code'] = seriesCode;
  80. }
  81. if (modelCode) {
  82. cond[0].$match['airAvg._id.model_code'] = modelCode;
  83. }
  84. const agg = [
  85. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  86. { $unwind: '$data' },
  87. ...cond,
  88. { $group: { _id: null, count: { $sum: '$data.count' },
  89. airDuration: { $sum: '$data.airDuration' },
  90. onCompressorDuration: { $sum: '$data.onCompressorDuration' },
  91. offCompressorDuration: { $sum: '$data.offCompressorDuration' },
  92. onAutoDuration: { $sum: '$data.onAutoDuration' },
  93. offAutoDuration: { $sum: '$data.offAutoDuration' },
  94. blowerRatingOneDuration: { $sum: '$data.blowerRatingOneDuration' },
  95. blowerRatingTwoDuration: { $sum: '$data.blowerRatingTwoDuration' },
  96. blowerRatingThreeDuration: { $sum: '$data.blowerRatingThreeDuration' },
  97. blowerRatingFourDuration: { $sum: '$data.blowerRatingFourDuration' },
  98. blowerRatingOtherDuration: { $sum: '$data.blowerRatingOtherDuration' } } },
  99. { $project: {
  100. airDuration: {
  101. $cond: {
  102. if: { $eq: [ '$count', 0 ] },
  103. then: 0, else: { $divide: [ '$airDuration', '$count' ] },
  104. },
  105. },
  106. onCompressorDuration: {
  107. $cond: {
  108. if: { $eq: [ '$count', 0 ] },
  109. then: 0, else: { $divide: [ '$onCompressorDuration', '$count' ] },
  110. },
  111. },
  112. offCompressorDuration: {
  113. $cond: {
  114. if: { $eq: [ '$count', 0 ] },
  115. then: 0, else: { $divide: [ '$offCompressorDuration', '$count' ] },
  116. },
  117. },
  118. onAutoDuration: {
  119. $cond: {
  120. if: { $eq: [ '$count', 0 ] },
  121. then: 0, else: { $divide: [ '$onAutoDuration', '$count' ] },
  122. },
  123. },
  124. offAutoDuration: {
  125. $cond: {
  126. if: { $eq: [ '$count', 0 ] },
  127. then: 0, else: { $divide: [ '$offAutoDuration', '$count' ] },
  128. },
  129. },
  130. blowerRatingOneDuration: {
  131. $cond: {
  132. if: { $eq: [ '$count', 0 ] },
  133. then: 0, else: { $divide: [ '$blowerRatingOneDuration', '$count' ] },
  134. },
  135. },
  136. blowerRatingTwoDuration: {
  137. $cond: {
  138. if: { $eq: [ '$count', 0 ] },
  139. then: 0, else: { $divide: [ '$blowerRatingTwoDuration', '$count' ] },
  140. },
  141. },
  142. blowerRatingThreeDuration: {
  143. $cond: {
  144. if: { $eq: [ '$count', 0 ] },
  145. then: 0, else: { $divide: [ '$blowerRatingThreeDuration', '$count' ] },
  146. },
  147. },
  148. blowerRatingFourDuration: {
  149. $cond: {
  150. if: { $eq: [ '$count', 0 ] },
  151. then: 0, else: { $divide: [ '$blowerRatingFourDuration', '$count' ] },
  152. },
  153. },
  154. blowerRatingOtherDuration: {
  155. $cond: {
  156. if: { $eq: [ '$count', 0 ] },
  157. then: 0, else: { $divide: [ '$blowerRatingOtherDuration', '$count' ] },
  158. },
  159. },
  160. } },
  161. ];
  162. const result = await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateNGroup(agg);
  163. return Object.assign({ airDuration: 0, onCompressorDuration: 0, offCompressorDuration: 0,
  164. onAutoDuration: 0, offAutoDuration: 0,
  165. blowerRatingOneDuration: 0, blowerRatingTwoDuration: 0, blowerRatingThreeDuration: 0,
  166. blowerRatingFourDuration: 0, blowerRatingOtherDuration: 0 }, result);
  167. }
  168. // 求位置维度数据(无时间分组)油耗平均
  169. async avgOil({ startTime, endTime, seriesCode, modelCode, level }) {
  170. const { ctx } = this;
  171. const obj = `oil${level.charAt(0).toUpperCase()}${level.slice(1)}`;
  172. const cond = [{ $match: {} }];
  173. if (seriesCode) {
  174. cond[0].$match[`${obj}._id.series_code`] = seriesCode;
  175. }
  176. if (modelCode) {
  177. cond[0].$match[`${obj}._id.model_code`] = modelCode;
  178. }
  179. const agg = [
  180. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  181. { $unwind: `$${obj}` },
  182. ...cond,
  183. { $group: { _id: `$${obj}._id._id`, name: { $first: `$${obj}.name` }, count: { $avg: `$${obj}.avgOil` } } },
  184. { $sort: { count: -1 } },
  185. { $project:
  186. {
  187. name: 1,
  188. count: { $divide: [{ $trunc: { $multiply: [ '$count', 100 ] } }, 100 ] },
  189. },
  190. },
  191. ];
  192. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  193. }
  194. // 求车辆某个维度数据之和(无时间分组)
  195. async sum({ startTime, endTime, seriesCode, modelCode }, vString) {
  196. const { ctx } = this;
  197. const cond = [{ $match: {} }];
  198. if (seriesCode) {
  199. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  200. }
  201. if (modelCode) {
  202. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  203. }
  204. const agg = [
  205. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  206. { $unwind: `$${vString}` },
  207. ...cond,
  208. { $group: { _id: `$${vString}._id._id`, count: { $sum: `$${vString}.count` } } },
  209. ];
  210. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  211. }
  212. // 基本方法 计算匹配的时间段下 过滤车型车系后时间分组下 维度分布分组数据平均值
  213. async avg({ type, startTime, endTime, seriesCode, modelCode }, vString) {
  214. const { ctx } = this;
  215. const cond = [{ $match: {} }];
  216. if (seriesCode) {
  217. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  218. }
  219. if (modelCode) {
  220. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  221. }
  222. const agg = [
  223. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  224. { $unwind: `$${vString}` },
  225. ...cond,
  226. ...ctx.helper.getCarAvgTimeGroupMongo(type, vString),
  227. ];
  228. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  229. }
  230. // 求平均值数据下某个维度 对应时间段的平均值
  231. async count({ type, startTime, endTime, seriesCode, modelCode }, vString) {
  232. const { ctx } = this;
  233. const cond = [{ $match: {} }];
  234. if (seriesCode) {
  235. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  236. }
  237. if (modelCode) {
  238. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  239. }
  240. const agg = [
  241. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  242. { $unwind: '$data' },
  243. ...cond,
  244. { $group: ctx.helper.getTimeGroup(type, {
  245. data: { $sum: `$data.${vString}` }, count: { $sum: '$data.count' },
  246. }) },
  247. { $project: {
  248. count:
  249. { $cond: { if: { $eq: [ '$count', 0 ] },
  250. then: 0, else: { $divide: [{ $trunc: { $multiply: [{ $divide: [ '$data', '$count' ] }, 100 ] } }, 100 ] } } },
  251. } },
  252. ];
  253. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  254. }
  255. // 求平均值数据下某个不是平均值(是总和)维度的数据 对应时间段的总和
  256. async count2({ type, startTime, endTime, seriesCode, modelCode }, vString) {
  257. const { ctx } = this;
  258. const cond = [{ $match: {} }];
  259. if (seriesCode) {
  260. cond[0].$match[`${vString}._id.series_code`] = seriesCode;
  261. }
  262. if (modelCode) {
  263. cond[0].$match[`${vString}._id.model_code`] = modelCode;
  264. }
  265. const agg = [
  266. { $match: ctx.helper.getTimeRangMatch(startTime, endTime) },
  267. { $unwind: '$data' },
  268. ...cond,
  269. { $group: ctx.helper.getTimeGroup(type, { count: { $sum: `$data.${vString}` } }) },
  270. ];
  271. return await ctx.model.Local.DrivingBehaviorInfoModel2.aggregateFix(agg);
  272. }
  273. // 统计清洗
  274. async statistics({ timeRangData, initData, isForceUpdate }) {
  275. const { ctx } = this;
  276. const hasData = await ctx.service.statisticsService.saveBefore(ctx.model.Local.DrivingBehaviorInfoModel2,
  277. { ...initData });
  278. if (hasData && !isForceUpdate) {
  279. return;
  280. }
  281. initData.start_time = new Date();
  282. const dHour = { $add: [{ $multiply: [{ $hour: { $toDate: '$$this.start_time' } }, 60 ] },
  283. { $minute: { $toDate: '$$this.start_time' } }] };
  284. const mileageCnt = await this.bucketGroup(timeRangData,
  285. { $toDouble: '$mileage_cnt' }, [ 0, 30, 60, 90, 120, 10 * 10000 ]);
  286. const mileage = await this.bucketGroup(timeRangData,
  287. { $toDouble: '$mileage' }, [ 0, 50, 100, 300, 500, 1000, 1500, 20000, 10000 * 10000 ]);
  288. const mileageAvg = await this.bucketGroup(timeRangData,
  289. { $cond: { if: { $eq: [{ $ifNull: [ '$mileage_cnt', 0 ] }, 0 ] },
  290. then: 0, else: { $divide: [{ $toDouble: '$mileage' }, { $toDouble: '$mileage_cnt' }] } } },
  291. [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 ]);
  292. const supplementaryCnt = await this.bucketGroup(timeRangData,
  293. { $toDouble: '$supplementary_cnt' }, [ 0, 1, 20, 30, 40, 50, 10 * 10000 ]);
  294. // const morningStart = 420;
  295. const morningStart = 0;
  296. // const morningEnd = 570;
  297. const morningEnd = 960;
  298. // const eveningStart = 17 * 60;
  299. const eveningStart = 960;
  300. // const eveningEnd = 19 * 60 + 30;
  301. const eveningEnd = 2000;
  302. const data = await this.avgGroup(timeRangData,
  303. {
  304. batterySoc: { $sum: { $toDouble: '$battery_soc' } },
  305. engineSpeed: { $sum: { $toDouble: '$engine_speed' } },
  306. insideTemperature: { $sum: { $toDouble: '$inside_temperature' } },
  307. outsideTemperature: { $sum: { $toDouble: '$outside_temperature' } },
  308. powerBatterySoc: { $sum: { $toDouble: '$power_battery_soc' } },
  309. chargeDuration: { $sum: { $divide: [{ $toDouble: '$charge_duration' }, 60 * 60 * 1000 ] } },
  310. chargeCnt: { $sum: { $toDouble: '$charge_cnt' } },
  311. skyDuration: { $sum: { $divide: [{ $toDouble: '$sky_duration' }, 60 * 1000 ] } },
  312. headlightCnt: { $sum: { $toDouble: '$headlight_cnt' } },
  313. headlightDuration: { $sum: { $divide: [{ $toDouble: '$headlight_duration' }, 60 * 1000 ] } },
  314. highBeamCnt: { $sum: { $toDouble: '$high_beam_cnt' } },
  315. highBeamDuration: { $sum: { $divide: [{ $toDouble: '$high_beam_duration' }, 60 * 1000 ] } },
  316. airDuration: { $sum: { $toDouble: '$air_duration' } },
  317. onCompressorDuration: { $sum: { $toDouble: '$on_compressor_duration' } },
  318. offCompressorDuration: { $sum: { $toDouble: '$off_compressor_duration' } },
  319. onAutoDuration: { $sum: { $toDouble: '$on_auto_duration' } },
  320. offAutoDuration: { $sum: { $toDouble: '$off_auto_duration' } },
  321. blowerRatingOneDuration: { $sum: { $toDouble: '$blower_rating_duration.one' } },
  322. blowerRatingTwoDuration: { $sum: { $toDouble: '$blower_rating_duration.two' } },
  323. blowerRatingThreeDuration: { $sum: { $toDouble: '$blower_rating_duration.three' } },
  324. blowerRatingFourDuration: { $sum: { $toDouble: '$blower_rating_duration.four' } },
  325. blowerRatingOtherDuration: { $sum: { $add: [{ $toDouble: '$blower_rating_duration.five' },
  326. { $toDouble: '$blower_rating_duration.six' }, { $toDouble: '$blower_rating_duration.seven' }] } },
  327. dsmCnt: { $sum: { $toDouble: '$dsm_cnt' } },
  328. atNightDriveCnt: { $sum: { $toDouble: '$at_night_drive_cnt' } },
  329. atNightDriveDuration: { $sum: { $divide: [{ $toDouble: '$at_night_drive_duration' }, 60 * 60 * 1000 ] } },
  330. atNightDriveMileage: { $sum: { $toDouble: '$at_night_drive_mileage' } },
  331. morningPeakDuration: { $sum: '$morningPeakDuration' },
  332. morningPeakMileage: { $sum: '$morningPeakMileage' },
  333. eveningPeakDuration: { $sum: '$eveningPeakDuration' },
  334. eveningPeakMileage: { $sum: '$eveningPeakMileage' },
  335. },
  336. [{ $addFields: {
  337. morningPeakDuration: { $ifNull: [
  338. { $sum: { $map: { input: '$mileage_list',
  339. in: { $cond: { if: { $and: [{ $gte: [ dHour, morningStart ] }, { $lt: [ dHour, morningEnd ] }] },
  340. then: { $divide: [{ $toDouble: '$$this.drive_duration' }, 60 * 60 * 1000 ] }, else: 0 } } } } }, 0 ] },
  341. morningPeakMileage: { $ifNull: [
  342. { $sum: { $map: { input: '$mileage_list',
  343. in: { $cond: { if: { $and: [{ $gte: [ dHour, morningStart ] }, { $lt: [ dHour, morningEnd ] }] },
  344. then: { $toDouble: '$$this.mileage' }, else: 0 } } } } }, 0 ] },
  345. eveningPeakDuration: { $ifNull: [
  346. { $sum: { $map: { input: '$mileage_list',
  347. in: { $cond: { if: { $and: [{ $gte: [ dHour, eveningStart ] }, { $lt: [ dHour, eveningEnd ] }] },
  348. then: { $divide: [{ $toDouble: '$$this.drive_duration' }, 60 * 60 * 1000 ] }, else: 0 } } } } }, 0 ] },
  349. eveningPeakMileage: { $ifNull: [
  350. { $sum: { $map: { input: '$mileage_list',
  351. in: { $cond: { if: { $and: [{ $gte: [ dHour, eveningStart ] }, { $lt: [ dHour, eveningEnd ] }] },
  352. then: { $toDouble: '$$this.mileage' }, else: 0 } } } } }, 0 ] },
  353. } }]
  354. );
  355. const batterySoc = await this.bucketGroup(timeRangData,
  356. { $toDouble: '$battery_soc' }, [ 0, 60, 70, 80, 90, 100 ]);
  357. const engineSpeed = await this.bucketGroup(timeRangData,
  358. { $toDouble: '$engine_speed' }, [ 0, 2000, 3000, 4000, 5000, 10000 * 10000 ]);
  359. const insideTemperature = await this.bucketGroup(timeRangData,
  360. { $toDouble: '$inside_temperature' }, [ -1000, 30, 35, 40, 45, 50 ]);
  361. const outsideTemperature = await this.bucketGroup(timeRangData,
  362. { $toDouble: '$outside_temperature' }, [ -1000, 0, 10, 20, 30, 1000 ]);
  363. const powerBatterySoc = await this.bucketGroup(timeRangData,
  364. { $toDouble: '$power_battery_soc' }, [ 0, 60, 70, 80, 90, 100 ]);
  365. const chargeDuration = await this.bucketGroup(timeRangData,
  366. { $divide: [{ $toDouble: '$charge_duration' }, 60 * 60 * 1000 ] }, [ 0, 1, 2, 3, 4, 24 ]);
  367. const chargeStartSoc = await this.bucketGroup(timeRangData, '$chargeStartSoc', [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ],
  368. [{ $addFields: { chargeStartSoc: { $ifNull: [
  369. { $avg: { $map: { input: '$charge_list', in: { $toDouble: '$$this.start_soc' } } } }, 0 ] } } }]);
  370. const chargeEndSoc = await this.bucketGroup(timeRangData, '$chargeEndSoc', [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ],
  371. [{ $addFields: { chargeEndSoc: { $ifNull: [
  372. { $avg: { $map: { input: '$charge_list', in: { $toDouble: '$$this.end_soc' } } } }, 0 ] } } }]);
  373. const chargePreStartMileage = await this.bucketGroup(timeRangData, '$chargePreStartMileage',
  374. [ 0, 50, 100, 150, 200, 250, 300, 350, 400 ],
  375. [{ $addFields: { chargePreStartMileage: { $ifNull: [
  376. { $avg: { $map: { input: '$charge_list', in: { $toDouble: '$$this.pre_start_mileage' } } } }, 0 ] } } }]);
  377. const chargeStartTime = await this.group(timeRangData, { $hour: { $toDate: '$charge_list.start_time' } },
  378. [{ $unwind: '$charge_list' }]
  379. );
  380. const chargeType = await this.group(timeRangData, { $toDouble: '$charge_list.charge_type' },
  381. [{ $unwind: '$charge_list' }]
  382. );
  383. const chargeMileage = await this.bucketGroup(timeRangData, '$chargeMileage',
  384. [ 0, 50, 100, 150, 200, 250, 300, 10000 * 10000 ],
  385. [{ $addFields: { chargeMileage: { $ifNull: [
  386. { $avg: { $map: { input: '$charge_list', in: { $toDouble: '$$this.mileage' } } } }, 0 ] } } }]);
  387. const avgSpeedPower = await this.bucketGroup(timeRangData,
  388. { $toDouble: '$avg_speed' }, [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 1000 ],
  389. [], { $sum: { $toDouble: '$v.avg_power_consumption' } },
  390. { avg_power_consumption: '$avg_power_consumption' });
  391. const actualMileage = await this.bucketGroup(timeRangData, '$actualMileage',
  392. [ 0, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 10000 * 10000 ],
  393. [{ $addFields: { actualMileage: { $ifNull: [
  394. { $avg: { $map: { input: '$actual_mileage_list', in: { $toDouble: '$$this.mileage' } } } }, 0 ] } } }]);
  395. const chargeCnt = await this.bucketGroup(timeRangData,
  396. { $toDouble: '$charge_cnt' }, [ 0, 50, 100, 150, 200, 10 * 10000 ]);
  397. const skyDuration = await this.bucketGroup(timeRangData, { $divide: [{ $toDouble: '$sky_duration' }, 60 * 1000 ] },
  398. [ 0, 30, 60, 120, 180, 24 * 60 ]);
  399. const headlightCnt = await this.bucketGroup(timeRangData, { $toDouble: '$headlight_cnt' },
  400. [ 0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 10 * 10000 ]);
  401. const headlightDuration = await this.bucketGroup(timeRangData, { $divide: [{ $toDouble: '$headlight_duration' }, 60 * 1000 ] },
  402. [ 0, 0.5, 1, 3, 5, 8, 10, 15, 20, 25, 30, 40, 50, 24 * 60 ]);
  403. const highBeamCnt = await this.bucketGroup(timeRangData, { $toDouble: '$high_beam_cnt' },
  404. [ 0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 10 * 10000 ]);
  405. const highBeamDuration = await this.bucketGroup(timeRangData, { $divide: [{ $toDouble: '$high_beam_duration' }, 60 * 1000 ] },
  406. [ 0, 0.5, 1, 3, 5, 8, 10, 15, 20, 25, 30, 40, 50, 24 * 60 ]);
  407. const mileageStartTimeAndDsm = await this.group(timeRangData, { $hour: { $toDate: '$mileage_list.start_time' } },
  408. [{ $unwind: '$mileage_list' }],
  409. { count: { $sum: 1 }, dsmCount: { $sum: { $cond: [{ $eq: [ '$mileage_list.dsm_status', 1 ] }, 1, 0 ] } } }
  410. );
  411. const mileageCnt2 = await this.bucketGroup(timeRangData, { $toDouble: '$mileage_cnt' },
  412. [ 0, 5, 10, 15, 20, 25, 30, 10 * 10000 ]
  413. );
  414. const avgSpeed = await this.bucketGroup(timeRangData, { $toDouble: '$avg_speed' },
  415. [ 0, 20, 30, 40, 50, 1000 ]
  416. );
  417. const driveDuration = await this.bucketGroup(timeRangData, { $toDouble: '$drive_duration' },
  418. [ 0, 1, 2, 3, 4, 24 ]
  419. );
  420. const continuousDrive = await this.bucketGroup(timeRangData,
  421. { $divide: [{ $toDouble: '$mileage_list.drive_duration' }, 60 * 60 * 1000 ] },
  422. [ 0, 1, 2, 3, 4, 24 ],
  423. [{ $unwind: '$mileage_list' }]
  424. );
  425. const driveStyle = await this.group(timeRangData, '$mileage_list.drive_style',
  426. [{ $unwind: '$mileage_list' }],
  427. { count: { $sum: 1 } }
  428. );
  429. const drivingSafetyScore = await this.bucketGroup(timeRangData, { $toDouble: '$driving_safety_score' },
  430. [ 0, 60, 75, 90, 101 ]
  431. );
  432. const energyConservationScore = await this.bucketGroup(timeRangData, { $toDouble: '$energy_conservation_score' },
  433. [ 0, 60, 75, 90, 101 ]
  434. );
  435. const mileageSingle = await this.bucketGroup(timeRangData, { $toDouble: '$mileage_list.mileage' },
  436. [ 0, 10, 20, 30, 40, 50 ],
  437. [{ $unwind: '$mileage_list' }]
  438. );
  439. const maxAcce = await this.bucketGroup(timeRangData, { $toDouble: '$mileage_list.max_acce' },
  440. [ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 ],
  441. [{ $unwind: '$mileage_list' }]
  442. );
  443. const maxDece = await this.bucketGroup(timeRangData, { $toDouble: '$mileage_list.max_dece' },
  444. [ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8 ],
  445. [{ $unwind: '$mileage_list' }]
  446. );
  447. const sideAcce = await this.bucketGroup(timeRangData, { $toDouble: '$mileage_list.side_acce' },
  448. [ 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 ],
  449. [{ $unwind: '$mileage_list' }]
  450. );
  451. const oilProvince = await this.oilLocation(timeRangData, { _id: '$car.pro_code' },
  452. [
  453. { $lookup: { from: 't_sync_province', localField: '_id._id', foreignField: 'out_pro_code', as: 'pro' } },
  454. { $unwind: '$pro' },
  455. { $project: { avgOil: 1, name: '$pro.province_name' } },
  456. ]);
  457. const oilCity = await this.oilLocation(timeRangData, { fid: '$car.pro_code', _id: '$car.city_code' },
  458. [
  459. { $lookup: { from: 't_sync_province', localField: '_id.fid', foreignField: 'out_pro_code', as: 'pro' } },
  460. { $unwind: '$pro' },
  461. { $lookup: {
  462. from: 't_sync_city',
  463. let: { city_code: '$_id._id', province_id: '$pro.province_id' },
  464. pipeline: [{ $match: { $expr: { $and:
  465. [
  466. { $eq: [ '$out_city_code', '$$city_code' ] },
  467. { $eq: [ '$province_id', '$$province_id' ] },
  468. ] } } }], as: 'city',
  469. } },
  470. { $unwind: '$city' },
  471. { $project: { avgOil: 1, name: '$city.city_name' } },
  472. ]);
  473. await this.ctx.service.statisticsService.save(this.ctx.model.Local.DrivingBehaviorInfoModel2,
  474. { ...initData,
  475. mileageCnt, mileage, supplementaryCnt, batterySoc, engineSpeed, insideTemperature, outsideTemperature,
  476. powerBatterySoc, chargeDuration, chargeStartSoc, chargeEndSoc, chargePreStartMileage, chargeStartTime,
  477. chargeType, chargeMileage, avgSpeedPower, actualMileage, chargeCnt,
  478. skyDuration, headlightCnt, headlightDuration, highBeamCnt, highBeamDuration,
  479. mileageStartTimeAndDsm, driveDuration, mileageCnt2, avgSpeed,
  480. continuousDrive, driveStyle, mileageSingle, mileageAvg,
  481. drivingSafetyScore, energyConservationScore,
  482. maxAcce, maxDece, sideAcce,
  483. data, oilProvince, oilCity,
  484. }, isForceUpdate);
  485. }
  486. async oilLocation({ startTime, endTime }, group, lookups) {
  487. const { ctx } = this;
  488. const agg = [
  489. { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'start_time') },
  490. { $lookup: { from: 't_vehicle_record', localField: 'vin', foreignField: 'vin', as: 'car' } },
  491. { $unwind: { path: '$car', preserveNullAndEmptyArrays: true } },
  492. { $group: {
  493. _id: { series_code: '$car.series_code', model_code: '$car.model_code', ...group },
  494. avgOil: { $avg: { $toDouble: '$avg_oil_consumption' } },
  495. } },
  496. ...lookups,
  497. ];
  498. return await ctx.model.DrivingBehaviorInfoModel.aggregateFix(agg);
  499. }
  500. async bucketGroup({ startTime, endTime }, group, boundaries, otherCond = [], sum, bucketF) {
  501. const { ctx } = this;
  502. const agg = [
  503. { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'start_time') },
  504. ...otherCond,
  505. ...ctx.helper.getBucketMongo(group, boundaries, sum, bucketF), // 保证在这步骤前必须有条件字段和vin即可
  506. ];
  507. return await ctx.model.DrivingBehaviorInfoModel.aggregateFix(agg);
  508. }
  509. async group({ startTime, endTime }, group, otherCond, cond = { count: { $sum: 1 } }) {
  510. const { ctx } = this;
  511. const agg = [
  512. { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'start_time') },
  513. ...otherCond,
  514. { $lookup: { from: 't_vehicle_record', localField: 'vin', foreignField: 'vin', as: 'car' } },
  515. { $unwind: { path: '$car', preserveNullAndEmptyArrays: true } },
  516. { $group: {
  517. _id: { series_code: '$car.series_code', model_code: '$car.model_code', _id: group },
  518. ...cond,
  519. } },
  520. ];
  521. return await ctx.model.DrivingBehaviorInfoModel.aggregateFix(agg);
  522. }
  523. async avgGroup({ startTime, endTime }, cond, otherCond) {
  524. const { ctx } = this;
  525. const agg = [
  526. { $match: ctx.helper.getTimeRangMatch(startTime, endTime, 'start_time') },
  527. ...otherCond,
  528. { $lookup: { from: 't_vehicle_record', localField: 'vin', foreignField: 'vin', as: 'car' } },
  529. { $unwind: { path: '$car', preserveNullAndEmptyArrays: true } },
  530. { $group: { _id: { series_code: '$car.series_code', model_code: '$car.model_code' },
  531. ...cond, count: { $sum: 1 } } },
  532. ];
  533. return await ctx.model.DrivingBehaviorInfoModel.aggregateFix(agg);
  534. }
  535. }
  536. module.exports = DrivingBehaviorInfoService2;