regenerate_duplicate_referral_ids.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. const VERBOSE_LOGGING = process.env.VERBOSE_LOGGING === 'true'
  2. const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY, 10) || 10
  3. const BATCH_SIZE = parseInt(process.env.BATCH_SIZE, 10) || 100
  4. // persist fallback in order to keep batchedUpdate in-sync
  5. process.env.BATCH_SIZE = BATCH_SIZE
  6. const { ReadPreference } = require('mongodb')
  7. const { db } = require('../app/src/infrastructure/mongodb')
  8. const { promiseMapWithLimit } = require('../app/src/util/promises')
  9. const TokenGenerator = require('../app/src/Features/TokenGenerator/TokenGenerator')
  10. const { batchedUpdate } = require('./helpers/batchedUpdate')
  11. async function rewriteDuplicates(duplicateReferralIds) {
  12. // duplicateReferralIds contains at least one duplicate.
  13. // Find out which is the duplicate in parallel and update
  14. // any users if necessary.
  15. await promiseMapWithLimit(
  16. WRITE_CONCURRENCY,
  17. duplicateReferralIds,
  18. async referralId => {
  19. try {
  20. const users = await db.users
  21. .find(
  22. { referal_id: referralId },
  23. {
  24. projection: { _id: 1 },
  25. readPreference: ReadPreference.SECONDARY,
  26. }
  27. )
  28. .toArray()
  29. if (users.length === 1) {
  30. // This referral id was part of a batch of duplicates.
  31. // Keep the write load low and skip the update.
  32. return
  33. }
  34. if (VERBOSE_LOGGING) {
  35. console.log('Found duplicate:', referralId)
  36. }
  37. for (const user of users) {
  38. const newReferralId = TokenGenerator.generateReferralId()
  39. await db.users.updateOne(
  40. { _id: user._id },
  41. {
  42. $set: {
  43. referal_id: newReferralId,
  44. },
  45. }
  46. )
  47. }
  48. } catch (error) {
  49. console.error(
  50. { err: error },
  51. `Failed to generate new referral ID for duplicate ID: ${referralId}`
  52. )
  53. }
  54. }
  55. )
  56. }
  57. async function processBatch(_, users) {
  58. const uniqueReferalIdsInBatch = Array.from(
  59. new Set(users.map(user => user.referal_id))
  60. )
  61. if (uniqueReferalIdsInBatch.length !== users.length) {
  62. if (VERBOSE_LOGGING) {
  63. console.log('Got duplicates from looking at batch.')
  64. }
  65. await rewriteDuplicates(uniqueReferalIdsInBatch)
  66. return
  67. }
  68. const matches = await db.users
  69. .find(
  70. { referal_id: { $in: uniqueReferalIdsInBatch } },
  71. {
  72. readPreference: ReadPreference.SECONDARY,
  73. projection: { _id: true },
  74. }
  75. )
  76. .toArray()
  77. if (matches.length !== uniqueReferalIdsInBatch.length) {
  78. if (VERBOSE_LOGGING) {
  79. console.log('Got duplicates from running count.')
  80. }
  81. await rewriteDuplicates(uniqueReferalIdsInBatch)
  82. }
  83. }
  84. async function main() {
  85. await batchedUpdate(
  86. 'users',
  87. { referal_id: { $exists: true } },
  88. processBatch,
  89. { _id: 1, referal_id: 1 }
  90. )
  91. }
  92. main()
  93. .then(() => {
  94. console.error('Done.')
  95. process.exit(0)
  96. })
  97. .catch(error => {
  98. console.error({ error })
  99. process.exit(1)
  100. })