Prechádzať zdrojové kódy

[migrations] add migration for back filling db.users.analyticsId (#33115)

* [migrations] add migration for back filling db.users.analyticsId

Co-authored-by: Davinder Singh <davinder.singh@overleaf.com>

* [web] add acceptance test for backfilling db.users.analyticsId

---------

Co-authored-by: Davinder Singh <davinder.singh@overleaf.com>
GitOrigin-RevId: a0840969ac0c4c84e874c6f00cf0a78857a4bb06
Jakob Ackermann 3 mesiacov pred
rodič
commit
50abfe8f0c

+ 99 - 0
services/web/test/acceptance/src/BackFillUsersAnalyticsId.mjs

@@ -0,0 +1,99 @@
+import { expect } from 'chai'
+import { db, ObjectId } from '../../../app/src/infrastructure/mongodb.mjs'
+import { exec } from 'node:child_process'
+
+describe('BackFillUsersAnalyticsId', function () {
+  beforeEach('insert data', async function () {
+    await db.users.insertMany([
+      {
+        _id: new ObjectId('50e434d90000000000000000'),
+        email: 'foo0@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000001'),
+        email: 'foo1@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000002'),
+        analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecd',
+        email: 'foo2@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000003'),
+        analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecf',
+        email: 'foo3@bar.com',
+      },
+    ])
+  })
+
+  beforeEach('run migration', function (done) {
+    exec(
+      'cd ../../tools/migrations && east migrate -t saas --force 20260424120000_back_fill_users_analyticsId',
+      done
+    )
+  })
+
+  it('should update the users', async function () {
+    expect(
+      await db.users
+        .find({}, { projection: { _id: 1, email: 1, analyticsId: 1 } })
+        .toArray()
+    ).to.deep.equal([
+      {
+        _id: new ObjectId('50e434d90000000000000000'),
+        analyticsId: '50e434d90000000000000000',
+        email: 'foo0@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000001'),
+        analyticsId: '50e434d90000000000000001',
+        email: 'foo1@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000002'),
+        analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecd',
+        email: 'foo2@bar.com',
+      },
+      {
+        _id: new ObjectId('50e434d90000000000000003'),
+        analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecf',
+        email: 'foo3@bar.com',
+      },
+    ])
+  })
+
+  describe('after rolling back', function () {
+    beforeEach(function (done) {
+      exec(
+        'cd ../../tools/migrations && east rollback -t saas --force 20260424120000_back_fill_users_analyticsId',
+        done
+      )
+    })
+    it('should update the users and roll back', async function () {
+      expect(
+        await db.users
+          .find({}, { projection: { _id: 1, email: 1, analyticsId: 1 } })
+          .toArray()
+      ).to.deep.equal([
+        {
+          _id: new ObjectId('50e434d90000000000000000'),
+          email: 'foo0@bar.com',
+        },
+        {
+          _id: new ObjectId('50e434d90000000000000001'),
+          email: 'foo1@bar.com',
+        },
+        {
+          _id: new ObjectId('50e434d90000000000000002'),
+          analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecd',
+          email: 'foo2@bar.com',
+        },
+        {
+          _id: new ObjectId('50e434d90000000000000003'),
+          analyticsId: '32dc5866-1451-4209-ba9d-23e96caafecf',
+          email: 'foo3@bar.com',
+        },
+      ])
+    })
+  })
+})

+ 24 - 0
tools/migrations/20260424120000_back_fill_users_analyticsId.mjs

@@ -0,0 +1,24 @@
+import { db } from './lib/mongodb.mjs'
+import { batchedUpdate } from '@overleaf/mongo-utils/batchedUpdate.js'
+
+const tags = ['saas', 'server-ce', 'server-pro']
+
+const migrate = async () => {
+  await batchedUpdate(db.users, { analyticsId: { $exists: false } }, [
+    { $set: { analyticsId: { $toString: '$_id' } } },
+  ])
+}
+
+const rollback = async () => {
+  await batchedUpdate(
+    db.users,
+    { $expr: { $eq: [{ $strLenCP: '$analyticsId' }, 24] } },
+    { $unset: { analyticsId: 1 } }
+  )
+}
+
+export default {
+  tags,
+  migrate,
+  rollback,
+}