123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /**
- * @class PageResult 页面结果统计模型
- */
- const BaseMod = require('./base')
- const Platform = require('./platform')
- const Channel = require('./channel')
- const Version = require('./version')
- const SessionLog = require('./sessionLog')
- const PageLog = require('./pageLog')
- const ShareLog = require('./shareLog')
- const {
- DateTime
- } = require('../lib')
- module.exports = class PageResult extends BaseMod {
- constructor() {
- super()
- this.tableName = 'page-result'
- this.platforms = []
- this.channels = []
- this.versions = []
- }
- /**
- * 数据统计
- * @param {String} type 统计类型 hour:实时统计 day:按天统计,week:按周统计 month:按月统计
- * @param {Date|Time} date 指定日期或时间戳
- * @param {Boolean} reset 是否重置,为ture时会重置该批次数据
- */
- async stat(type, date, reset) {
- //允许的类型
- const allowedType = ['day']
- if (!allowedType.includes(type)) {
- return {
- code: 1002,
- msg: 'This type is not allowed'
- }
- }
- this.fillType = type
- //获取当前统计的时间范围
- const dateTime = new DateTime()
- const dateDimension = dateTime.getTimeDimensionByType(type, -1, date)
- this.startTime = dateDimension.startTime
- this.endTime = dateDimension.endTime
- if (this.debug) {
- console.log('dimension time', this.startTime + '--' + this.endTime)
- }
- // 查看当前时间段日志是否已存在,防止重复执行
- if (!reset) {
- const checkRes = await this.getCollection(this.tableName).where({
- start_time: this.startTime,
- end_time: this.endTime
- }).get()
- if (checkRes.data.length > 0) {
- console.error('This page stat log have exists')
- return {
- code: 1003,
- msg: 'This page stat log have existed'
- }
- }
- } else {
- const delRes = await this.delete(this.tableName, {
- start_time: this.startTime,
- end_time: this.endTime
- })
- console.log('Delete old data result:', JSON.stringify(delRes))
- }
- // 数据获取
- this.pageLog = new PageLog()
- const statRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- page_id: 1,
- create_time: 1
- },
- match: {
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: {
- _id: {
- appid: '$appid',
- version: '$version',
- platform: '$platform',
- channel: '$channel',
- page_id: '$page_id'
- },
- visit_times: {
- $sum: 1
- }
- },
- sort: {
- visit_times: 1
- },
- getAll: true
- })
- let res = {
- code: 0,
- msg: 'success'
- }
- if (this.debug) {
- console.log('Page statRes', JSON.stringify(statRes))
- }
- if (statRes.data.length > 0) {
- this.fillData = []
- //获取填充数据
- for (const i in statRes.data) {
- await this.fill(statRes.data[i])
- }
- //数据批量入库
- if (this.fillData.length > 0) {
- res = await this.batchInsert(this.tableName, this.fillData)
- }
- }
- return res
- }
- /**
- * 页面统计数据填充
- * @param {Object} data 统计数据
- */
- async fill(data) {
- // 平台信息
- let platformInfo = null
- if (this.platforms && this.platforms[data._id.platform]) {
- //暂存下数据,减少读库
- platformInfo = this.platforms[data._id.platform]
- } else {
- const platform = new Platform()
- platformInfo = await platform.getPlatformAndCreate(data._id.platform, null)
- if (!platformInfo || platformInfo.length === 0) {
- platformInfo._id = ''
- }
- this.platforms[data._id.platform] = platformInfo
- if (this.debug) {
- console.log('platformInfo', JSON.stringify(platformInfo))
- }
- }
- // 渠道信息
- let channelInfo = null
- const channelKey = data._id.appid + '_' + platformInfo._id + '_' + data._id.channel
- if (this.channels && this.channels[channelKey]) {
- channelInfo = this.channels[channelKey]
- } else {
- const channel = new Channel()
- channelInfo = await channel.getChannelAndCreate(data._id.appid, platformInfo._id, data._id.channel)
- if (!channelInfo || channelInfo.length === 0) {
- channelInfo._id = ''
- }
- this.channels[channelKey] = channelInfo
- if (this.debug) {
- console.log('channelInfo', JSON.stringify(channelInfo))
- }
- }
- // 版本信息
- let versionInfo = null
- const versionKey = data._id.appid + '_' + data._id.platform + '_' + data._id.version
- if (this.versions && this.versions[versionKey]) {
- versionInfo = this.versions[versionKey]
- } else {
- const version = new Version()
- versionInfo = await version.getVersionAndCreate(data._id.appid, data._id.platform, data._id.version)
- if (!versionInfo || versionInfo.length === 0) {
- versionInfo._id = ''
- }
- this.versions[versionKey] = versionInfo
- if (this.debug) {
- console.log('versionInfo', JSON.stringify(versionInfo))
- }
- }
- const matchCondition = data._id
- Object.assign(matchCondition, {
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- })
- if (this.debug) {
- console.log('matchCondition', JSON.stringify(matchCondition))
- }
- // 当前页面访问设备数
- const statPageDeviceRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- device_id: 1,
- page_id: 1,
- create_time: 1
- },
- match: matchCondition,
- group: [{
- _id: {
- device_id: '$device_id'
- }
- }, {
- _id: {},
- total_devices: {
- $sum: 1
- }
- }]
- })
- let pageVisitDevices = 0
- if (statPageDeviceRes.data.length > 0) {
- pageVisitDevices = statPageDeviceRes.data[0].total_devices
- }
- // 当前页面访问人数
- const statPageUserRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- uid: 1,
- page_id: 1,
- create_time: 1
- },
- match: {
- ...matchCondition,
- uid: {
- $ne: ''
- }
- },
- group: [{
- _id: {
- uid: '$uid'
- }
- }, {
- _id: {},
- total_users: {
- $sum: 1
- }
- }]
- })
- let pageVisitUsers = 0
- if (statPageUserRes.data.length > 0) {
- pageVisitUsers = statPageUserRes.data[0].total_users
- }
- // 退出次数
- const sessionLog = new SessionLog()
- let existTimes = 0
- const existRes = await this.getCollection(sessionLog.tableName).where({
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- exit_page_id: data._id.page_id,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- }).count()
- if (existRes && existRes.total > 0) {
- existTimes = existRes.total
- }
- // 访问时长
- const statPageDurationRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- previous_page_id: 1,
- previous_page_duration: 1,
- create_time: 1
- },
- match: {
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- previous_page_id: data._id.page_id,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: {
- _id: {},
- total_duration: {
- $sum: '$previous_page_duration'
- }
- }
- })
- let totalDuration = 0
- if (statPageDurationRes.data.length > 0) {
- totalDuration = statPageDurationRes.data[0].total_duration
- }
- // 分享次数
- const shareLog = new ShareLog()
- const statShareRes = await this.aggregate(shareLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- page_id: 1,
- create_time: 1
- },
- match: {
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- page_id: data._id.page_id,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: {
- _id: {},
- share_count: {
- $sum: 1
- }
- }
- })
- let shareCount = 0
- if (statShareRes.data.length > 0) {
- shareCount = statShareRes.data[0].share_count
- }
- // 作为入口页的总次数和总访问时长
- const statPageEntryCountRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- previous_page_id: 1,
- previous_page_duration: 1,
- previous_page_is_entry: 1,
- create_time: 1
- },
- match: {
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- previous_page_id: data._id.page_id,
- previous_page_is_entry: 1,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: {
- _id: {},
- entry_count: {
- $sum: 1
- },
- entry_duration: {
- $sum: '$previous_page_duration'
- }
- }
- })
- let entryCount = 0
- let entryDuration = 0
- if (statPageEntryCountRes.data.length > 0) {
- entryCount = statPageEntryCountRes.data[0].entry_count
- entryDuration = statPageEntryCountRes.data[0].entry_duration
- }
- // 作为入口页的总设备数
- const statPageEntryDevicesRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- device_id: 1,
- previous_page_id: 1,
- previous_page_is_entry: 1,
- create_time: 1
- },
- match: {
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- previous_page_id: data._id.page_id,
- previous_page_is_entry: 1,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: [{
- _id: {
- device_id: '$device_id'
- }
- }, {
- _id: {},
- entry_devices: {
- $sum: 1
- }
- }]
- })
- let entryDevices = 0
- if (statPageEntryDevicesRes.data.length > 0) {
- entryDevices = statPageEntryDevicesRes.data[0].entry_devices
- }
- // 作为入口页的总人数
- const statPageEntryUsersRes = await this.aggregate(this.pageLog.tableName, {
- project: {
- appid: 1,
- version: 1,
- platform: 1,
- channel: 1,
- uid: 1,
- previous_page_id: 1,
- previous_page_is_entry: 1,
- create_time: 1
- },
- match: {
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- previous_page_id: data._id.page_id,
- previous_page_is_entry: 1,
- uid: {
- $ne: ''
- },
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- },
- group: [{
- _id: {
- uid: '$uid'
- }
- }, {
- _id: {},
- entry_users: {
- $sum: 1
- }
- }]
- })
- let entryUsers = 0
- if (statPageEntryUsersRes.data.length > 0) {
- entryUsers = statPageEntryUsersRes.data[0].entry_users
- }
- // 跳出率
- let bounceTimes = 0
- const bounceRes = await this.getCollection(sessionLog.tableName).where({
- appid: data._id.appid,
- version: data._id.version,
- platform: data._id.platform,
- channel: data._id.channel,
- entry_page_id: data._id.page_id,
- page_count: 1,
- create_time: {
- $gte: this.startTime,
- $lte: this.endTime
- }
- }).count()
- if (bounceRes && bounceRes.total > 0) {
- bounceTimes = bounceRes.total
- }
- let bounceRate = 0
- if (bounceTimes > 0 && data.visit_times > 0) {
- bounceRate = bounceTimes * 100 / data.visit_times
- bounceRate = parseFloat(bounceRate.toFixed(2))
- }
- // 数据填充
- const datetime = new DateTime()
- const insertParams = {
- appid: data._id.appid,
- platform_id: platformInfo._id,
- channel_id: channelInfo._id,
- version_id: versionInfo._id,
- page_id: data._id.page_id,
- visit_times: data.visit_times,
- visit_devices: pageVisitDevices,
- visit_users: pageVisitUsers,
- exit_times: existTimes,
- duration: totalDuration > 0 ? totalDuration : 1,
- share_count: shareCount,
- entry_users: entryUsers,
- entry_devices: entryDevices,
- entry_count: entryCount,
- entry_duration: entryDuration,
- bounce_rate: bounceRate,
- dimension: this.fillType,
- stat_date: datetime.getDate('Ymd', this.startTime),
- start_time: this.startTime,
- end_time: this.endTime
- }
- this.fillData.push(insertParams)
- return insertParams
- }
- }
|