首页 > 解决方案 > 如何使用猫鼬对填充的两级深子文档数组进行排序

问题描述

我正在用 mongoose 和 nodejs 开发一个 api。

基本上有课程模型、学生模型和小组模型。对于每门课程,课程文档中有两个字段:

. 字段“学生”:引用学生模型的对象 ID 数组。

. 字段“groups”:子文档数组,每个子文档都有一个“groupId”字段引用 Group Model 和一个“students”字段:一个 objectids 引用 Student Model 的数组。这些是按课程分组的学生。

我可以按课程获取排序的学生列表,但无法按组获取此列表。我可以得到未排序的列表,但未排序。

这些是我的主要模式:

组模型-> 组集合:

const groupSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    unique: true
  }
})

学生模型 -> 学生集合:

const studentSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    index:true
  },
  firstName: {
    type: String,
    required: true,
    index:true
  },
  lastName: {
    type: String,
    required: true,
    index:true
  }
})

课程模型 -> 课程集合:

const courseSchema = new mongoose.Schema({
  name: {
    type: String,
    required: true,
    index: true
  },
  students: [
    {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Student'
    }
  ],
  groups: [
    {
      groupId: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Group'
      },
      students: [
        {
          type: mongoose.Schema.Types.ObjectId,
          ref: 'Student'    
        }
      ],
    }
  ]
})

使用下一个查询,我得到一个按课程字母顺序排序的学生列表,即使我可以使用“where”进行过滤而不会出现问题:

const query = await Course.findById(courseId)
    .select('students')
    .populate({
      path: 'students',
      select: ['_id', 'firstName', 'lastName', 'name'],
      match: where,
      options: {
        sort: {
          firstName: 1,
          lastName: 1,
          name: 1
        }
      }
    })

这个查询很好,但我想要另一个查询按组和课程返回有序的学生列表。我正在使用类似的查询,但使用嵌套的子文档数组:

  const query = await Course.findById(courseId)
    .where('groups.groupId').equals(groupId)
    .select('groups.$.students')
    .populate({
      path: 'groups.students',
      select: ['_id', 'firstName', 'lastName', 'name'],
      match: where,
      // options: {
      //   sort: {
      //     firstName: 1,
      //     lastName: 1,
      //     name: 1
      //   }
      // }
    })

这样我得到了学生名单,但没有排序。如果我取消注释对填充列表进行排序的选项,我会收到错误消息:

“无法填充sort路径 groups.students,因为它是文档数组的子属性”。

在我使用 sql 数据库之前,我是 mongodb 的新手,但我正在使用 mongoose 学习 mongodb。我不知道我的架构设计是否能最好地得到我想要的。

由于这不起作用,为了解决问题,我将“排序”方法应用于查询进行排序,如下所示:

  query.groups[0].students.sort((st1, st2) => {
    if (st1.firstName > st2.firstName) return 1
    if (st1.lastName > st2.lastName) return 1
    if (st1.name > st2.name) return 1
    return -1
  })

有没有办法使用查询和/或填充方法来获得这个?

按照有关 mongodb 聚合框架的专家建议,我找到了解决问题的第一种方法。我用过的聚合:

db.courses.aggregate([
    { $match: { _id: ObjectId("5c6d43c98068bc0836a62b65") }},
    { $project: {
        _id: 0,
        groups: '$groups'
        }
    },
    { $unwind: "$groups" },
    { $match: { 'groups.groupId': ObjectId("5c94b0d81ce16357d74549dd") }},
    { $project: {
        students: '$groups.students'
    }},
    { $unwind: '$students' },
    { $lookup: {
        from: "students",
        localField: "students",
        foreignField: "_id",
        as: "students"
    }},
    { $project: {
        id: { $arrayElemAt: [ "$students._id", 0 ] },
        nie: { $arrayElemAt: [ "$students.nie", 0 ] },
        name: { $arrayElemAt: [ "$students.name", 0 ] },
        firstName: { $arrayElemAt: [ "$students.firstName", 0 ] },
        lastName: { $arrayElemAt: [ "$students.lastName", 0 ] }
    }},
    { $sort: { firstName: 1, lastName: 1, name: 1 } }
])

标签: mongodbmongooseschemapopulate

解决方案


推荐阅读