mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
Added members.email_open_rate aggregation to email analytics (#12458)
refs https://github.com/TryGhost/Ghost/issues/12421 requires https://github.com/TryGhost/Ghost/pull/12457 - updates stats aggregator to calculate and store an open rate for each member - uses two queries because I couldn't find a reasonable approach to perform the update in a single query as per the email aggregation - benchmarked locally at <1sec/1000members - will not store an open rate unless the number of tracked emails sent to a member is above a certain threshold (defaults to 5) to avoid new members being heavily weighted - fixes typo in EmailAnalytics that was stopping member stats from being aggregated
This commit is contained in:
parent
9fd6f30fd7
commit
567eb6325f
4 changed files with 22 additions and 6 deletions
|
@ -81,7 +81,7 @@ class EmailAnalyticsService {
|
|||
await this.aggregateEmailStats(emailId);
|
||||
}
|
||||
for (const memberId of memberIds) {
|
||||
await this.aggregateEmailStats(memberId);
|
||||
await this.aggregateMemberStats(memberId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ if (parentPort) {
|
|||
const aggregateEndDate = new Date();
|
||||
debug(`Finished aggregating email analytics in ${aggregateEndDate - aggregateStartDate}ms`);
|
||||
|
||||
logging.info(`Fetched ${eventStats.totalEvents} events and aggregated stats for ${eventStats.emailIds.length} emails in ${aggregateEndDate - fetchStartDate}ms`);
|
||||
logging.info(`Fetched ${eventStats.totalEvents} events and aggregated stats for ${eventStats.emailIds.length} emails and ${eventStats.memberIds.length} members in ${aggregateEndDate - fetchStartDate}ms`);
|
||||
|
||||
if (parentPort) {
|
||||
parentPort.postMessage('done');
|
||||
|
|
|
@ -51,7 +51,7 @@ if (parentPort) {
|
|||
const aggregateEndDate = new Date();
|
||||
debug(`Finished aggregating email analytics in ${aggregateEndDate - aggregateStartDate}ms`);
|
||||
|
||||
logging.info(`Fetched ${eventStats.totalEvents} events and aggregated stats for ${eventStats.emailIds.length} emails in ${aggregateEndDate - fetchStartDate}ms`);
|
||||
logging.info(`Fetched ${eventStats.totalEvents} events and aggregated stats for ${eventStats.emailIds.length} emails and ${eventStats.memberIds.length} members in ${aggregateEndDate - fetchStartDate}ms`);
|
||||
|
||||
if (parentPort) {
|
||||
parentPort.postMessage('done');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class EmailAnalyticsStatsAggregator {
|
||||
constructor({logging, db}) {
|
||||
constructor({options, logging, db}) {
|
||||
this.options = Object.assign({openRateEmailThreshold: 5}, options);
|
||||
this.logging = logging || console;
|
||||
this.db = db;
|
||||
}
|
||||
|
@ -12,8 +13,23 @@ class EmailAnalyticsStatsAggregator {
|
|||
}).where('id', emailId);
|
||||
}
|
||||
|
||||
async aggregateMember(/*memberId*/) {
|
||||
// TODO: decide on aggregation algorithm when only certain emails have open tracking
|
||||
async aggregateMember(memberId) {
|
||||
const {trackedEmailCount} = await this.db.knex('email_recipients')
|
||||
.select(this.db.knex.raw('COUNT(email_recipients.id) as trackedEmailCount'))
|
||||
.leftJoin('emails', 'email_recipients.email_id', 'emails.id')
|
||||
.where('email_recipients.member_id', memberId)
|
||||
.where('emails.track_opens', true)
|
||||
.first() || {};
|
||||
|
||||
if (trackedEmailCount >= this.options.openRateEmailThreshold) {
|
||||
await this.db.knex('members')
|
||||
.update({
|
||||
email_open_rate: this.db.knex.raw(`(
|
||||
(SELECT COUNT(id) FROM email_recipients WHERE member_id = ? AND opened_at IS NOT NULL) * 1.0 / ? * 100)
|
||||
`, [memberId, trackedEmailCount])
|
||||
})
|
||||
.where('id', memberId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue