MongoDB +mongoose连接和高级查询

7eumitmz  于 2023-02-07  发布在  Go
关注(0)|答案(1)|浏览(157)

我的数据库模式很复杂,我想改进当前的查询
在我的用户集合中,我有一个数组组,其中包含此用户相关的组。当用户登录时,我会查找以下所有任务:
1.任务处于活动状态
1.当前日期介于task.fromDate和task.toDate之间
1.任务位于与当前用户相关的组中
1.组.active为真
foreach任务,我想得到相关的行动(任务)和相关的响应(用户+任务).
我的数据库模式在这里是https://mongoplayground.net/p/X9iAEzwDEWa
我当前的代码正在运行多个查询,我希望改进此查询这是我当前的代码

const {groups} = await User.findOne({ username, active:true })
    .select("groups")
    .lean()
    .exec();
   const tasksQuery = {
    active: true,
    group: { $in: groups },
    $or: [
      {
        fromDate: {
          $exists: false,
        },
        toDate: {
          $exists: false,
        },
      },
      {
        $expr: {
          $and: [
            {
              $lte: ["$fromDate", "$$NOW"],
            },
            {
              $gte: ["$toDate", "$$NOW"],
            },
          ],
        },
      },
    ],
  };
 const tasks =  await Task.find(tasksQuery).lean()

  const tasksWithGroup = await Promise.all(
    tasks.map(async (task) => {
      const group = await Group.findById(task.group).lean().exec();
      const actions =  await Action.find({task:task._id, active:true}).select("_id").lean().exec();
      const numActions = actions?.length
      let doneActions = 0
      let gradeActions=0
      let responses=[]
      //get data for student
      if(numActions && req.isStudent){
        responses = await Response.find({username:req.user ,action:{ $in: actions } }).select(["_id","grade"]).lean().exec()
        if(responses.length) {
          doneActions = responses.length
          gradeActions = responses.filter(c=>c.grade > -1).length
        }
      }
      return { ...task, groupname: group?.name , numActions, actions,doneActions ,gradeActions, responses};
    })
  );
b5buobof

b5buobof1#

您的方案存在几个问题。
1.分散收集:MongoDB不是一个关系数据库。$lookup/连接集合的开销可能很大。您可能需要重构您的模式以反规范化并将频繁访问的记录放在同一个集合中。
1.您正在依赖应用程序级筛选:如果可能,应该利用数据库级筛选
1.您正在触发多个db调用以获取数据:您可以使用$lookup在一个单独的db调用中获取聚合管道中所需的数据。
在不深入研究模式重构的情况下,模式重构需要更多的实际场景背景,而且不适合单个堆栈溢出问题的焦点要求,下面是一个经过调整的查询版本:

db.users.aggregate([
  {
    "$match": {
      "_id": {
        "$oid": "6390a187bd6b97a4dc58263d"
      }
    }
  },
  {
    "$lookup": {
      "from": "groups",
      "localField": "groups",
      "foreignField": "_id",
      "pipeline": [
        {
          $match: {
            "active": true
          }
        }
      ],
      "as": "groups"
    }
  },
  {
    "$unwind": "$groups"
  },
  {
    "$lookup": {
      "from": "tasks",
      "localField": "groups._id",
      "foreignField": "group",
      "pipeline": [
        {
          $match: {
            $expr: {
              $and: [
                {
                  active: true
                },
                {
                  $gte: [
                    "$$NOW",
                    "$fromDate"
                  ]
                },
                {
                  $lte: [
                    "$$NOW",
                    "$toDate"
                  ]
                }
              ]
            }
          }
        }
      ],
      "as": "tasks"
    }
  },
  {
    "$unwind": "$tasks"
  },
  {
    "$lookup": {
      "from": "responses",
      "localField": "tasks._id",
      "foreignField": "task",
      "pipeline": [],
      "as": "responses"
    }
  },
  {
    "$unwind": {
      path: "$responses",
      preserveNullAndEmptyArrays: true
    }
  }
])

Mongo Playground
其思想是链接$lookup中的集合,并依赖于子管道来执行过滤。

相关问题