Taichi Masuyama 4 лет назад
Родитель
Сommit
147ed7f565
2 измененных файлов с 34 добавлено и 21 удалено
  1. 1 1
      packages/app/src/server/routes/apiv3/pages.js
  2. 33 20
      packages/app/src/server/service/page.js

+ 1 - 1
packages/app/src/server/routes/apiv3/pages.js

@@ -681,7 +681,7 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  // TODO: use job to show progress
+  // TODO: use socket conn to show progress
   router.get('/v5-schema-migration', /* accessTokenParser, loginRequired, adminRequired, csrf, */ async(req, res) => {
   router.get('/v5-schema-migration', /* accessTokenParser, loginRequired, adminRequired, csrf, */ async(req, res) => {
     try {
     try {
       const Page = crowi.model('Page');
       const Page = crowi.model('Page');

+ 33 - 20
packages/app/src/server/service/page.js

@@ -741,6 +741,7 @@ class PageService {
   async v5RecursiveMigration(grant, rootPath = null) {
   async v5RecursiveMigration(grant, rootPath = null) {
     const BATCH_SIZE = 100;
     const BATCH_SIZE = 100;
     const Page = this.crowi.model('Page');
     const Page = this.crowi.model('Page');
+    const { PageQueryBuilder } = Page;
 
 
     const randomPagesStream = await Page
     const randomPagesStream = await Page
       .aggregate([
       .aggregate([
@@ -773,25 +774,39 @@ class PageService {
     const migratePagesStream = new Writable({
     const migratePagesStream = new Writable({
       objectMode: true,
       objectMode: true,
       async write(pages, encoding, callback) {
       async write(pages, encoding, callback) {
+        // make list to create empty pages
+        const parentPathsSet = new Set(pages.map(page => pathlib.dirname(page.path)));
+        const parentPaths = Array.from(parentPathsSet);
+
+        // find existing parents
+        const builder1 = new PageQueryBuilder(Page.find({}, { _id: 0, path: 1 }));
+        const existingParents = await builder1
+          .addConditionToListByPathsArray(parentPaths)
+          .query
+          .lean()
+          .exec();
+        const existingParentPaths = existingParents.map(parent => parent.path);
+
+        // paths to create empty pages
+        const notExistingParentPaths = parentPaths.filter(path => !existingParentPaths.includes(path));
+
+        // insertMany empty pages
+        await Page.insertMany(notExistingParentPaths.map(path => ({ path, isEmpty: true })));
+
+        // find parents again
+        const builder2 = new PageQueryBuilder(Page.find({}, { _id: 1, path: 1 }));
+        const parents = await builder2
+          .addConditionToListByPathsArray(parentPaths)
+          .query
+          .lean()
+          .exec();
+
         // bulkWrite to update parent
         // bulkWrite to update parent
-        const updateManyOperations = await Promise.all(pages.map(async(page) => {
-          const parentPath = pathlib.dirname(page.path);
-
-          // get parent OR create an empty page as a parent
-          let parent = await Page.findOne({ path: parentPath }).select({ _id: 1 }).lean().exec();
-          if (parent == null) {
-            try {
-              parent = await (new Page({ path: parentPath, isEmpty: true })).save();
-            }
-            catch (err) {
-              logger.error('Couldnt create parent', err);
-              throw err;
-            }
-          }
+        const updateManyOperations = parents.map((parent) => {
           const parentId = parent._id;
           const parentId = parent._id;
 
 
           // modify to adjust for RegExp
           // modify to adjust for RegExp
-          const parentPathForRegexp = parentPath === '/' ? parentPath : '';
+          const parentPath = parent.path === '/' ? '' : parent.path;
 
 
           // TODO: consider filter to improve the target selection
           // TODO: consider filter to improve the target selection
           return {
           return {
@@ -799,15 +814,14 @@ class PageService {
               filter: {
               filter: {
                 // regexr.com/6889f
                 // regexr.com/6889f
                 // ex. /parent/any_child OR /any_level1
                 // ex. /parent/any_child OR /any_level1
-                path: { $regex: new RegExp(`^${parentPathForRegexp}(\\/[^/]+)\\/?$`, 'g') },
+                path: { $regex: new RegExp(`^${parentPath}(\\/[^/]+)\\/?$`, 'g') },
               },
               },
               update: {
               update: {
                 parent: parentId,
                 parent: parentId,
               },
               },
             },
             },
           };
           };
-        }));
-
+        });
         await Page.bulkWrite(updateManyOperations);
         await Page.bulkWrite(updateManyOperations);
 
 
         callback();
         callback();
@@ -822,8 +836,7 @@ class PageService {
       .pipe(migratePagesStream);
       .pipe(migratePagesStream);
 
 
     await streamToPromise(migratePagesStream);
     await streamToPromise(migratePagesStream);
-
-    if ((await Page.exists({ grant, parent: null }))) {
+    if (await Page.exists({ grant, parent: null })) {
       await this.v5RecursiveMigration(grant, rootPath);
       await this.v5RecursiveMigration(grant, rootPath);
     }
     }
   }
   }