get_emails_by_ids.mjs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import { scriptRunner } from './lib/ScriptRunner.mjs'
  2. import fs from 'node:fs'
  3. import readline from 'node:readline'
  4. import minimist from 'minimist'
  5. import { db, ObjectId } from '../app/src/infrastructure/mongodb.js'
  6. /**
  7. * This script extracts user emails given a list of newline separated IDs
  8. *
  9. * Usage:
  10. * - Locally:
  11. * - docker compose exec web bash
  12. * - node scripts/get_emails_by_ids.mjs
  13. * - On the server:
  14. * - rake run:pod[staging,web]
  15. * - node scripts/get_emails_by_ids.mjs
  16. * - exit
  17. * - kubectl cp web-standalone-prod-XXXXX:/tmp/emails.txt ~/emails.txt
  18. */
  19. function usage() {
  20. console.log(
  21. `
  22. User email extraction, outputs to /tmp/emails.txt
  23. Usage:
  24. node scripts/get_emails_by_ids.js [--inputPath=<path>] [--outputPath=<path>] [--batchSize=<number>]
  25. Options:
  26. --help Show this screen
  27. --inputPath=<path> Input file path (default: ids.txt)
  28. --outputPath=<path> Output file path (default: /tmp/emails.txt)
  29. --batchSize=<number> Number of emails to be fetched in one query
  30. Description:
  31. This script extracts user emails given a list of newline separated IDs
  32. `
  33. )
  34. }
  35. function parseArgs() {
  36. const argv = minimist(process.argv.slice(2), {
  37. string: ['inputPath', 'outputPath'],
  38. bool: ['help'],
  39. number: ['batchSize'],
  40. default: {
  41. help: false,
  42. inputPath: 'ids.txt',
  43. outputPath: '/tmp/emails.txt',
  44. batchSize: 1000,
  45. },
  46. })
  47. if (argv.help) {
  48. usage()
  49. process.exit(0)
  50. }
  51. return argv
  52. }
  53. async function processBatch(idBatch, writeStream) {
  54. try {
  55. const cursor = db.users
  56. .find({
  57. _id: { $in: idBatch },
  58. })
  59. .project({
  60. _id: 0,
  61. email: 1,
  62. })
  63. for await (const doc of cursor) {
  64. if (doc.email) {
  65. writeStream.write(doc.email + '\n')
  66. }
  67. }
  68. } catch (err) {
  69. console.error('Error processing batch:', err)
  70. }
  71. }
  72. async function main(trackProgress) {
  73. const args = parseArgs()
  74. const readStream = fs.createReadStream(args.inputPath)
  75. const writeStream = fs.createWriteStream(args.outputPath)
  76. const rl = readline.createInterface({
  77. input: readStream,
  78. crlfDelay: Infinity,
  79. })
  80. let idBatch = []
  81. for await (const line of rl) {
  82. const id = line.trim()
  83. if (id) {
  84. try {
  85. idBatch.push(new ObjectId(id))
  86. } catch (e) {
  87. console.warn(`Skipping invalid ObjectId: ${id}`)
  88. }
  89. }
  90. if (idBatch.length >= args.batchSize) {
  91. await processBatch(idBatch, writeStream)
  92. idBatch = []
  93. }
  94. }
  95. if (idBatch.length > 0) {
  96. await processBatch(idBatch, writeStream)
  97. }
  98. writeStream.end()
  99. console.log(`✅ Success! Found emails written to ${args.outputPath}`)
  100. await trackProgress('Job finished')
  101. }
  102. try {
  103. await scriptRunner(main)
  104. process.exit(0)
  105. } catch (error) {
  106. console.error(error)
  107. process.exit(1)
  108. }