back_fill_dummy_doc_meta.mjs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import mongodb from 'mongodb'
  2. import { db, READ_PREFERENCE_SECONDARY } from '../lib/mongodb.mjs'
  3. const { ObjectId } = mongodb
  4. const NOW_IN_S = Date.now() / 1000
  5. const ONE_WEEK_IN_S = 60 * 60 * 24 * 7
  6. const DUMMY_NAME = 'unknown.tex'
  7. const DUMMY_TIME = new Date('2021-04-12T00:00:00.000Z')
  8. let deletedProjectsCache = null
  9. function getSecondsFromObjectId(id) {
  10. return id.getTimestamp().getTime() / 1000
  11. }
  12. async function main(firstProjectId) {
  13. const options = {
  14. firstProjectId,
  15. incrementByS: parseInt(process.env.INCREMENT_BY_S, 10) || ONE_WEEK_IN_S,
  16. batchSize: parseInt(process.env.BATCH_SIZE, 10) || 1000,
  17. stopAtS: parseInt(process.env.STOP_AT_S, 10) || NOW_IN_S,
  18. }
  19. deletedProjectsCache = new Map()
  20. let startId = options.firstProjectId
  21. let nProcessed = 0
  22. while (getSecondsFromObjectId(startId) <= options.stopAtS) {
  23. const end = getSecondsFromObjectId(startId) + options.incrementByS
  24. let endId = ObjectId.createFromTime(end)
  25. const query = {
  26. project_id: {
  27. // include edge
  28. $gte: startId,
  29. // exclude edge
  30. $lt: endId,
  31. },
  32. deleted: true,
  33. name: {
  34. $exists: false,
  35. },
  36. }
  37. const docs = await db.docs
  38. .find(query, { readPreference: READ_PREFERENCE_SECONDARY })
  39. .project({ _id: 1, project_id: 1 })
  40. .limit(options.batchSize)
  41. .toArray()
  42. if (docs.length) {
  43. const docIds = docs.map(doc => doc._id)
  44. console.log('Back filling dummy meta data for', JSON.stringify(docIds))
  45. await processBatch(docs, options)
  46. nProcessed += docIds.length
  47. if (docs.length === options.batchSize) {
  48. endId = docs[docs.length - 1].project_id
  49. }
  50. }
  51. console.error('Processed %d until %s', nProcessed, endId)
  52. startId = endId
  53. }
  54. }
  55. async function getDeletedProject(projectId) {
  56. const cacheKey = projectId.toString()
  57. if (deletedProjectsCache.has(cacheKey)) {
  58. return deletedProjectsCache.get(cacheKey)
  59. }
  60. const deletedProject = await db.deletedProjects.findOne(
  61. { 'deleterData.deletedProjectId': projectId },
  62. {
  63. projection: {
  64. _id: 1,
  65. 'project.deletedDocs': 1,
  66. },
  67. }
  68. )
  69. deletedProjectsCache.set(cacheKey, deletedProject)
  70. return deletedProject
  71. }
  72. async function processBatch(docs, options) {
  73. for (const doc of docs) {
  74. const { _id: docId, project_id: projectId } = doc
  75. const deletedProject = await getDeletedProject(projectId)
  76. let name = DUMMY_NAME
  77. let deletedAt = DUMMY_TIME
  78. if (deletedProject) {
  79. const project = deletedProject.project
  80. if (project) {
  81. const deletedDoc =
  82. project.deletedDocs &&
  83. project.deletedDocs.find(deletedDoc => docId.equals(deletedDoc._id))
  84. if (deletedDoc) {
  85. console.log('Found deletedDoc for %s', docId)
  86. name = deletedDoc.name
  87. deletedAt = deletedDoc.deletedAt
  88. } else {
  89. console.log('Missing deletedDoc for %s', docId)
  90. }
  91. } else {
  92. console.log('Orphaned deleted doc %s (failed hard deletion)', docId)
  93. }
  94. } else {
  95. console.log('Orphaned deleted doc %s (no deletedProjects entry)', docId)
  96. }
  97. await db.docs.updateOne({ _id: docId }, { $set: { name, deletedAt } })
  98. }
  99. }
  100. export default main