You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
canteen/uniCloud-aliyun/cloudfunctions/common/uni-stat/stat/mod/loyalty.js

492 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 设备/用户忠诚度(粘性)统计模型
*/
const BaseMod = require('./base')
const Platform = require('./platform')
const Channel = require('./channel')
const Version = require('./version')
const SessionLog = require('./sessionLog')
const UserSessionLog = require('./userSessionLog')
const {
DateTime
} = require('../lib')
module.exports = class Loyalty extends BaseMod {
constructor() {
super()
this.tableName = 'loyalty-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('this time', dateTime.getTime())
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.log('loyalty log have existed')
return {
code: 1003,
msg: 'This 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.sessionLog = new SessionLog()
const statRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
duration: 1,
create_time: 1
},
match: {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
},
group: {
_id: {
appid: '$appid',
version: '$version',
platform: '$platform',
channel: '$channel'
},
page_count_sum: {
$sum: '$page_count'
},
duration_sum: {
$sum: '$duration'
}
},
sort: {
page_count_sum: 1,
duration_sum: 1
},
getAll: true
})
let res = {
code: 0,
msg: 'success'
}
if (this.debug) {
console.log('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 pageMark = [1, 2, 3, 4, [5, 10], [10]]
const matchCondition = Object.assign(data._id, {
create_time: {
$gte: this.startTime,
$lte: this.endTime
}
})
const visitDepthData = {
visit_devices: {},
visit_users: {},
visit_times: {}
}
const userSessionLog = new UserSessionLog()
//根据各访问页面数区间统计
for (const pi in pageMark) {
let pageMarkCondition = {
page_count: pageMark[pi]
}
if (Array.isArray(pageMark[pi])) {
if (pageMark[pi].length === 2) {
pageMarkCondition = {
page_count: {
$gte: pageMark[pi][0],
$lte: pageMark[pi][1]
}
}
} else {
pageMarkCondition = {
page_count: {
$gt: pageMark[pi][0]
}
}
}
}
// 访问次数(会话次数)统计
const searchCondition = {
...matchCondition,
...pageMarkCondition
}
const vistRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1
},
match: searchCondition,
group: {
_id: {},
total_visits: {
$sum: 1
}
}
})
if (this.debug) {
console.log('vistResCondtion', JSON.stringify(searchCondition))
console.log('vistRes', JSON.stringify(vistRes))
}
let vistCount = 0
if (vistRes.data.length > 0) {
vistCount = vistRes.data[0].total_visits
}
// 设备数统计
const deviceRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1,
device_id: 1
},
match: searchCondition,
group: [{
_id: {
device_id: '$device_id'
}
}, {
_id: {},
total_devices: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('searchCondition', JSON.stringify(searchCondition))
console.log('deviceRes', JSON.stringify(deviceRes))
}
let deviceCount = 0
if (deviceRes.data.length > 0) {
deviceCount = deviceRes.data[0].total_devices
}
// 用户数统计
const userRes = await this.aggregate(userSessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
page_count: 1,
create_time: 1,
uid: 1
},
match: searchCondition,
group: [{
_id: {
uid: '$uid'
}
}, {
_id: {},
total_users: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userResCondtion', JSON.stringify(searchCondition))
console.log('userRes', JSON.stringify(userRes))
}
let userCount = 0
if (userRes.data.length > 0) {
userCount = userRes.data[0].total_users
}
const pageKey = 'p_' + (Array.isArray(pageMark[pi]) ? pageMark[pi][0] : pageMark[pi])
visitDepthData.visit_devices[pageKey] = deviceCount
visitDepthData.visit_users[pageKey] = userCount
visitDepthData.visit_times[pageKey] = vistCount
}
// 访问时长-用户数统计和访问次数
const durationMark = [
[0, 2],
[3, 5],
[6, 10],
[11, 20],
[21, 30],
[31, 50],
[51, 100],
[100]
]
const durationData = {
visit_devices: {},
visit_users: {},
visit_times: {}
}
//根据各访问时长区间统计
for (const di in durationMark) {
let durationMarkCondition = {
duration: durationMark[di]
}
if (Array.isArray(durationMark[di])) {
if (durationMark[di].length === 2) {
durationMarkCondition = {
duration: {
$gte: durationMark[di][0],
$lte: durationMark[di][1]
}
}
} else {
durationMarkCondition = {
duration: {
$gt: durationMark[di][0]
}
}
}
}
// 访问次数(会话次数)统计
const searchCondition = {
...matchCondition,
...durationMarkCondition
}
if (this.debug) {
console.log('searchCondition', JSON.stringify(searchCondition))
}
const vistRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: {
_id: {},
total_visits: {
$sum: 1
}
}
})
if (this.debug) {
console.log('vistRes', JSON.stringify(vistRes))
}
let vistCount = 0
if (vistRes.data.length > 0) {
vistCount = vistRes.data[0].total_visits
}
// 设备数统计
const deviceRes = await this.aggregate(this.sessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
device_id: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: [{
_id: {
device_id: '$device_id'
}
}, {
_id: {},
total_devices: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userRes', JSON.stringify(deviceRes))
}
let deviceCount = 0
if (deviceRes.data.length > 0) {
deviceCount = deviceRes.data[0].total_devices
}
// 用户数统计
const userRes = await this.aggregate(userSessionLog.tableName, {
project: {
appid: 1,
version: 1,
platform: 1,
channel: 1,
uid: 1,
duration: 1,
create_time: 1
},
match: searchCondition,
group: [{
_id: {
uid: '$uid'
}
}, {
_id: {},
total_users: {
$sum: 1
}
}]
})
if (this.debug) {
console.log('userRes', JSON.stringify(userRes))
}
let userCount = 0
if (userRes.data.length > 0) {
userCount = userRes.data[0].total_users
}
const pageKey = 's_' + (Array.isArray(durationMark[di]) ? durationMark[di][0] : durationMark[di])
durationData.visit_devices[pageKey] = deviceCount
durationData.visit_users[pageKey] = userCount
durationData.visit_times[pageKey] = vistCount
}
// 数据填充
const datetime = new DateTime()
const insertParams = {
appid: data._id.appid,
platform_id: platformInfo._id,
channel_id: channelInfo._id,
version_id: versionInfo._id,
visit_depth_data: visitDepthData,
duration_data: durationData,
stat_date: datetime.getDate('Ymd', this.startTime),
start_time: this.startTime,
end_time: this.endTime
}
this.fillData.push(insertParams)
return insertParams
}
}