NGTools/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/pageResult.js

523 lines
12 KiB
JavaScript
Raw Normal View History

/**
* @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
}
}