backfill_mixpanel_user_properties.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY, 10) || 10
  2. require('../app/src/models/User')
  3. const { batchedUpdateWithResultHandling } = require('./helpers/batchedUpdate')
  4. const { promiseMapWithLimit } = require('../app/src/util/promises')
  5. const { getQueue } = require('../app/src/infrastructure/Queues')
  6. const SubscriptionLocator = require('../app/src/Features/Subscription/SubscriptionLocator')
  7. const PlansLocator = require('../app/src/Features/Subscription/PlansLocator')
  8. const FeaturesHelper = require('../app/src/Features/Subscription/FeaturesHelper')
  9. const mixpanelSinkQueue = getQueue('analytics-mixpanel-sink')
  10. async function processUser(user) {
  11. const analyticsId = user.analyticsId || user._id
  12. await _sendPropertyToQueue(analyticsId, 'user-id', user._id)
  13. await _sendPropertyToQueue(analyticsId, 'analytics-id', analyticsId)
  14. await _sendPropertyToQueue(analyticsId, 'created-at', user.signUpDate)
  15. if (user.alphaProgram !== undefined) {
  16. await _sendPropertyToQueue(analyticsId, 'alpha-program', user.alphaProgram)
  17. }
  18. if (user.betaProgram !== undefined) {
  19. await _sendPropertyToQueue(analyticsId, 'beta-program', user.betaProgram)
  20. }
  21. const groupSubscriptionPlanCode = await _getGroupSubscriptionPlanCode(
  22. user._id
  23. )
  24. if (groupSubscriptionPlanCode) {
  25. await _sendPropertyToQueue(
  26. analyticsId,
  27. 'group-subscription-plan-code',
  28. groupSubscriptionPlanCode
  29. )
  30. }
  31. const matchedFeatureSet = FeaturesHelper.getMatchedFeatureSet(user.features)
  32. if (matchedFeatureSet !== 'personal') {
  33. await _sendPropertyToQueue(analyticsId, 'feature-set', matchedFeatureSet)
  34. }
  35. if (user.splitTests) {
  36. for (const splitTestName of Object.keys(user.splitTests)) {
  37. const assignments = user.splitTests[splitTestName]
  38. if (Array.isArray(assignments)) {
  39. for (const assignment of assignments) {
  40. await _sendPropertyToQueue(
  41. analyticsId,
  42. `split-test-${splitTestName}-${assignment.versionNumber}`,
  43. `${assignment.variantName}`
  44. )
  45. }
  46. }
  47. }
  48. }
  49. }
  50. async function _getGroupSubscriptionPlanCode(userId) {
  51. const subscriptions =
  52. await SubscriptionLocator.promises.getMemberSubscriptions(userId)
  53. let bestPlanCode = null
  54. let bestFeatures = {}
  55. for (const subscription of subscriptions) {
  56. const plan = PlansLocator.findLocalPlanInSettings(subscription.planCode)
  57. if (
  58. plan &&
  59. FeaturesHelper.isFeatureSetBetter(plan.features, bestFeatures)
  60. ) {
  61. bestPlanCode = plan.planCode
  62. bestFeatures = plan.features
  63. }
  64. }
  65. return bestPlanCode
  66. }
  67. async function _sendPropertyToQueue(
  68. analyticsId,
  69. propertyName,
  70. propertyValue,
  71. createdAt = new Date()
  72. ) {
  73. if (propertyValue == null) {
  74. return
  75. }
  76. await mixpanelSinkQueue.add('user-property', {
  77. analyticsId,
  78. propertyName,
  79. propertyValue,
  80. createdAt,
  81. })
  82. }
  83. async function processBatch(_, users) {
  84. await promiseMapWithLimit(WRITE_CONCURRENCY, users, async user => {
  85. await processUser(user)
  86. })
  87. }
  88. batchedUpdateWithResultHandling(
  89. 'users',
  90. {
  91. $nor: [
  92. { thirdPartyIdentifiers: { $exists: false } },
  93. { thirdPartyIdentifiers: { $size: 0 } },
  94. ],
  95. },
  96. processBatch,
  97. {
  98. _id: true,
  99. analyticsId: true,
  100. signUpDate: true,
  101. splitTests: true,
  102. alphaProgram: true,
  103. betaProgram: true,
  104. }
  105. )