-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Add weighted mean with the migration fixes #28458
base: master
Are you sure you want to change the base?
fix: Add weighted mean with the migration fixes #28458
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
This PR adds weighted mean calculation functionality for retention insights and fixes migration issues that caused dashboard failures. Here's a summary of the key changes:
- Added RetentionMeanDropdown component with options for 'none', 'simple', and 'weighted' mean calculations in
/frontend/src/scenes/insights/filters/RetentionMeanDropdown.tsx
- Modified schema to change
showMean
from boolean to string enum ('none', 'simple', 'weighted') in/frontend/src/queries/schema.json
- Added migration script in
/posthog/migrations/0560_migrate_retention_show_mean.py
to convert existing boolean values to string format - Fixed bug in
RetentionTable.tsx
to exclude cohorts with 0 users from mean calculations - Updated test files to reflect new string-based mean type instead of boolean
The changes appear well-structured and address both the weighted mean feature request and the zero-user cohort bug while ensuring backward compatibility.
💡 (5/5) You can turn off certain types of comments like style here!
17 file(s) reviewed, 5 comment(s)
Edit PR Review Bot Settings | Greptile
const { retentionFilter } = useValues(insightVizDataLogic(insightProps)) | ||
const { updateInsightFilter } = useActions(insightVizDataLogic(insightProps)) | ||
|
||
const showMean = retentionFilter?.showMean || RETENTION_MEAN_NONE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Default fallback to RETENTION_MEAN_NONE is correct but could be more explicit with nullish coalescing (??) instead of logical OR (||) to handle edge cases where showMean is intentionally set to false
onChange={(showMean) => { | ||
updateInsightFilter({ showMean }) | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider adding type safety by explicitly typing the onChange parameter as RetentionMeanType
onChange={(showMean) => { | |
updateInsightFilter({ showMean }) | |
}} | |
onChange={(showMean: RetentionMeanType) => { | |
updateInsightFilter({ showMean }) | |
}} |
const weights = validRows.map((row) => | ||
parseInt(row[1]?.toString() || '0') | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: parseInt without radix parameter could lead to unexpected results with certain string formats. Consider using parseInt(x, 10) for explicit base-10 parsing.
const weights = validRows.map((row) => | |
parseInt(row[1]?.toString() || '0') | |
) | |
const weights = validRows.map((row) => | |
parseInt(row[1]?.toString() || '0', 10) | |
) |
return !( | ||
(columnIndex >= row.length - 1 && isLatestPeriod) || | ||
!row[columnIndex] || | ||
row[columnIndex].count <= 0 | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: The row filtering logic is duplicated between weighted and simple mean calculations. Consider extracting this into a shared helper function.
) | ||
|
||
for insight in retention_insights.iterator(chunk_size=100): | ||
show_mean_value = insight.query["source"]["retentionFilter"]["showMean"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Accessing nested dictionary keys without .get() could raise KeyError if structure is malformed
📸 UI snapshots have been updated12 snapshot changes in total. 0 added, 12 modified, 0 deleted:
Triggered by this commit. |
Size Change: 0 B Total Size: 1.18 MB ℹ️ View Unchanged
|
📸 UI snapshots have been updated32 snapshot changes in total. 0 added, 32 modified, 0 deleted:
Triggered by this commit. |
a594a3b
to
8e50320
Compare
📸 UI snapshots have been updated22 snapshot changes in total. 0 added, 22 modified, 0 deleted:
Triggered by this commit. |
📸 UI snapshots have been updated10 snapshot changes in total. 0 added, 10 modified, 0 deleted:
Triggered by this commit. |
… bool values for showMean
599b8e0
to
537f6e6
Compare
📸 UI snapshots have been updated1 snapshot changes in total. 0 added, 1 modified, 0 deleted:
Triggered by this commit. |
📸 UI snapshots have been updated1 snapshot changes in total. 0 added, 1 modified, 0 deleted:
Triggered by this commit. |
Problem
This PR fixes the issues with the migration in this PR. The issues with the migration caused dashboards for certain customers to fail.
The original PR added the functionality to allow our customers to get a weighted mean for their retention insights. It also fixes a bug where cohort sizes of 0 were being included in the mean calculations.
All the changes from the original PR are included in this one since it was reverted.
Closes #25998
Closes #26217
Changes
No mean
Simple Mean
6-bea6-19c71efdaad4" />Weighted Mean
👉 Stay up-to-date with PostHog coding conventions for a smoother review.
Does this work well for both Cloud and self-hosted?
How did you test this code?
Tested locally.