Просмотр исходного кода

implement method to update descendantCount of page

yohei0125 4 лет назад
Родитель
Сommit
8e7933f327
2 измененных файлов с 79 добавлено и 0 удалено
  1. 20 0
      packages/app/src/server/models/page.ts
  2. 59 0
      packages/app/src/server/service/page.js

+ 20 - 0
packages/app/src/server/models/page.ts

@@ -355,6 +355,26 @@ schema.statics.findAncestorsChildrenByPathAndViewer = async function(path: strin
   return pathToChildren;
 };
 
+schema.statics.findAllDescendantsByPath = async function(path, grant = 1) {
+  return this.aggregate(
+    [
+      { $match: { path: { $regex: `^${path}.*` }, grant } },
+      // https://regex101.com/r/8R3Meh/1
+      {
+        $project: {
+          path: 1,
+          parent: 1,
+          descendantCount: 1,
+          field_length: { $strLenCP: '$path' },
+        },
+      },
+
+      { $sort: { field_length: -1 } },
+      { $project: { field_length: 0 } },
+    ],
+  );
+};
+
 
 /*
  * Merge obsolete page model methods and define new methods which depend on crowi instance

+ 59 - 0
packages/app/src/server/service/page.js

@@ -30,6 +30,8 @@ class PageService {
 
     // init
     this.initPageEvent();
+    // this code is written to check if method works. will delete in the end.
+    this.updateAllDescendantCount().then(res => logger.info(res)).catch(err => logger.warn(err));
   }
 
   initPageEvent() {
@@ -1245,6 +1247,63 @@ class PageService {
     return Page.count({ parent: null, creator: user, grant: { $ne: Page.GRANT_PUBLIC } });
   }
 
+
+  async updateAllDescendantCount(path = '/', grant = 1) {
+    const Page = mongoose.model('Page');
+
+    /**
+     * retrieve all public descendants pages starting from path arg sorted descending order
+     * /A/B/C
+     * /A/B
+     * /A
+     */
+    const publicPages = await Page.findAllDescendantsByPath(path, grant);
+    for (const parentPage of publicPages) {
+
+      // find pages with parentPage._id set in the parent field
+      const childrenPages = publicPages.filter((childPage) => {
+        if (childPage.parent == null) return;
+        return childPage.parent.toString() === parentPage._id.toString();
+      });
+
+      // if children not exist, set descendantCount to 0
+      if (childrenPages.length === 0) {
+        try {
+          // eslint-disable-next-line no-await-in-loop
+          await Page.findOneAndUpdate({ _id: parentPage._id }, { $set: { descendantCount: 0 } });
+        }
+        catch (err) {
+          logger.warn(err);
+        }
+      }
+      else {
+        // if children exist, set descendantCount of parent page by following fomula.
+        // sum of children + sum of descendantCount that each children have in descendantCount field
+        try {
+          // aggregate the sum of descendantCount of parent page
+          // eslint-disable-next-line no-await-in-loop
+          const res = await Page.aggregate([
+            { $match: { parent: parentPage._id } },
+            {
+              $group: {
+                _id: null,
+                sumOfDescendantCount: { $sum: '$descendantCount' },
+              },
+            },
+          ]);
+          const sumOfDescendantCountArray = res.map(res => res.sumOfDescendantCount);
+          const totalDescendantCount = sumOfDescendantCountArray.reduce((prev, current) => prev + current);
+
+          // eslint-disable-next-line no-await-in-loop
+          await Page.findOneAndUpdate({ _id: parentPage._id }, { $set: { descendantCount: childrenPages.length + totalDescendantCount } });
+        }
+        catch (err) {
+          logger.warn(err);
+        }
+      }
+    }
+  }
+
 }
 
 module.exports = PageService;