最新消息: 电脑我帮您提供丰富的电脑知识,编程学习,软件下载,win7系统下载。

运行大量计划的MongoDB查询

IT培训 admin 12浏览 0评论

运行大量计划的MongoDB查询

问题:我有一个项目列表,这些项目的到期时间必须通过调度程序进行检查。如果项目已过期,则必须在数据库中将其标记。

我有超过2k的项目列表变得越来越繁琐(使用我当前的逻辑运行)。我也在使用node-schedule。我将其设置为45分钟(这并不理想,现在开始拖动)

问题:如何优化此计划作业?因为如果可能的话,我希望这些到期可以实时进行。我正在使用projects[x].activities[y].status.expiredprojects[x].activities[y].status.startTime

模式

const StudentSchema= new Schema({
...
 projects: [
    {
      title: {
        type: String,
        required: [true, "Title is required for Project"]
      },

      activities: [
        {
          name: {
            type: String,
            required: true
          },
          gradingMechanism: {
            type: String,
            enum: ["Peer to Peer", "Mentor", "Instructor"]
          },
          totalPointsPossible: { type: Number },
          status: {
            text: {
              type: String,
              enum: [
                "Not Started",
                "Started",
                "Awaiting Grade",
                "Passing",
                "Failing"
              ],
              default: "Not Started"
            },
            graded: { type: Boolean, default: false },
            grade: { type: Number, default: 0 },
            pass: { type: Boolean, default: false },
            expired: { type: Boolean, default: false },
            completed: { type: Boolean, default: false },
            lastSave: { type: Date },
            hasStarted: { type: Boolean, default: false },
            startTime: { type: Date },
            completionTime: { type: Date }
          }
            }
          ],


        }
      ],
...

CODE

  // Expire Activities in Projects
  schedule.scheduleJob("*/45 * * * *", async function () {
    const profile = await StudentProfile.find({});

    StudentProfile.find(
      { "projects.activities.status.expired": { $eq: false } },
      "projects"
    )
      .then((profiles) => {
        let promiseList = [];
        profiles.map((profile) => {
          const { projects } = profile;
          let saveProfile = false;

          projects.map((project, projKey) => {
            project.activities.map((activity, actKey) => {
              if (
                typeof activity.status.startTime !== "undefined" &&
                !activity.status.expired
              ) {
                var startTime = new Date(activity.status.startTime);
                var activityTimeout = 72;
                // If startTime+<X TIME> is less than or equal to current time,
                // Mark activity as expired
                if (
                  startTime.setHours(startTime.getHours() + activityTimeout) <=
                  new Date()
                ) {
                  profile.projects[projKey].activities[
                    actKey
                  ].status.expired = true;
                  profile.projects[projKey].activities[actKey].status.text =
                    "Awaiting Grade";
                  saveProfile = true;
                }
              }
            });
          });
          if (saveProfile) {
            promiseList.push(profile.save());
          }
        });

        Promise.all(promiseList)
          .then((profiles) => {
            if (profiles.length > 0) {
              console.log("Marked " + profiles.length + " profile's projects");
            }
          })
          .catch((err) => {
            console.error(err);
          });
      })
      .catch((err) => {
        console.error(err);
      });
  })
回答如下:

当前,您的实现使用多个嵌套循环来评估返回的数据,从而达到您的要求。

这可以简化,使用数据库来满足此要求的一部分。使用$ where语句和带有计算出的到期日期的startTime,这是一个简单的条件,消除了大多数所需的循环。

而不是返回所有未过期记录的列表,而是返回满足过期条件的所有记录的列表。 (理论上,该数量应小于未过期记录的数量)。

为了达到要求的另一部分,您将执行最后的操作(更新),因为您知道这些记录已过期(因为它们符合您的条件)。

应该可以大大改善计划作业的性能,您不再需要评估代码中的返回值,而仅执行更新操作(这是您无法避免的事情。)>]

这里的主要问题是复杂性,您要遍历数组多次以评估不同的条件,每个其他项目都会增加处理时间和内存使用量。

TL; DR:MongoDB的部分不必很沉重,可以使用某种方法(甚至不是上面的方法)来减轻它的负担,找到一种不太复杂的方式来处理工作负载。

  • https://mongoosejs/docs/api/query.html#query_Query-gt
  • https://mongoosejs/docs/api/schema.html#schema_Schema-pre
  • 关于.pre选项,我什至会考虑对过期时间的作业进行预先调度,这也是简化逻辑的一种方式。

我个人使用Bull,Bull包含用于延迟/计划工作的机制,因此,这几乎是您寻求的实时解决方案。您需要在节点计划中找到等效的方法。

运行大量计划的MongoDB查询

问题:我有一个项目列表,这些项目的到期时间必须通过调度程序进行检查。如果项目已过期,则必须在数据库中将其标记。

我有超过2k的项目列表变得越来越繁琐(使用我当前的逻辑运行)。我也在使用node-schedule。我将其设置为45分钟(这并不理想,现在开始拖动)

问题:如何优化此计划作业?因为如果可能的话,我希望这些到期可以实时进行。我正在使用projects[x].activities[y].status.expiredprojects[x].activities[y].status.startTime

模式

const StudentSchema= new Schema({
...
 projects: [
    {
      title: {
        type: String,
        required: [true, "Title is required for Project"]
      },

      activities: [
        {
          name: {
            type: String,
            required: true
          },
          gradingMechanism: {
            type: String,
            enum: ["Peer to Peer", "Mentor", "Instructor"]
          },
          totalPointsPossible: { type: Number },
          status: {
            text: {
              type: String,
              enum: [
                "Not Started",
                "Started",
                "Awaiting Grade",
                "Passing",
                "Failing"
              ],
              default: "Not Started"
            },
            graded: { type: Boolean, default: false },
            grade: { type: Number, default: 0 },
            pass: { type: Boolean, default: false },
            expired: { type: Boolean, default: false },
            completed: { type: Boolean, default: false },
            lastSave: { type: Date },
            hasStarted: { type: Boolean, default: false },
            startTime: { type: Date },
            completionTime: { type: Date }
          }
            }
          ],


        }
      ],
...

CODE

  // Expire Activities in Projects
  schedule.scheduleJob("*/45 * * * *", async function () {
    const profile = await StudentProfile.find({});

    StudentProfile.find(
      { "projects.activities.status.expired": { $eq: false } },
      "projects"
    )
      .then((profiles) => {
        let promiseList = [];
        profiles.map((profile) => {
          const { projects } = profile;
          let saveProfile = false;

          projects.map((project, projKey) => {
            project.activities.map((activity, actKey) => {
              if (
                typeof activity.status.startTime !== "undefined" &&
                !activity.status.expired
              ) {
                var startTime = new Date(activity.status.startTime);
                var activityTimeout = 72;
                // If startTime+<X TIME> is less than or equal to current time,
                // Mark activity as expired
                if (
                  startTime.setHours(startTime.getHours() + activityTimeout) <=
                  new Date()
                ) {
                  profile.projects[projKey].activities[
                    actKey
                  ].status.expired = true;
                  profile.projects[projKey].activities[actKey].status.text =
                    "Awaiting Grade";
                  saveProfile = true;
                }
              }
            });
          });
          if (saveProfile) {
            promiseList.push(profile.save());
          }
        });

        Promise.all(promiseList)
          .then((profiles) => {
            if (profiles.length > 0) {
              console.log("Marked " + profiles.length + " profile's projects");
            }
          })
          .catch((err) => {
            console.error(err);
          });
      })
      .catch((err) => {
        console.error(err);
      });
  })
回答如下:

当前,您的实现使用多个嵌套循环来评估返回的数据,从而达到您的要求。

这可以简化,使用数据库来满足此要求的一部分。使用$ where语句和带有计算出的到期日期的startTime,这是一个简单的条件,消除了大多数所需的循环。

而不是返回所有未过期记录的列表,而是返回满足过期条件的所有记录的列表。 (理论上,该数量应小于未过期记录的数量)。

为了达到要求的另一部分,您将执行最后的操作(更新),因为您知道这些记录已过期(因为它们符合您的条件)。

应该可以大大改善计划作业的性能,您不再需要评估代码中的返回值,而仅执行更新操作(这是您无法避免的事情。)>]

这里的主要问题是复杂性,您要遍历数组多次以评估不同的条件,每个其他项目都会增加处理时间和内存使用量。

TL; DR:MongoDB的部分不必很沉重,可以使用某种方法(甚至不是上面的方法)来减轻它的负担,找到一种不太复杂的方式来处理工作负载。

  • https://mongoosejs/docs/api/query.html#query_Query-gt
  • https://mongoosejs/docs/api/schema.html#schema_Schema-pre
  • 关于.pre选项,我什至会考虑对过期时间的作业进行预先调度,这也是简化逻辑的一种方式。

我个人使用Bull,Bull包含用于延迟/计划工作的机制,因此,这几乎是您寻求的实时解决方案。您需要在节点计划中找到等效的方法。

与本文相关的文章

发布评论

评论列表 (0)

  1. 暂无评论