使用猫鼬获取/查找子项集合

时间:2019-12-03 18:47:44

标签: node.js mongodb mongoose

我是MongoDB的新手。我在嵌套集合时遇到了一些问题。假设我在mongodb中有3个不同的集合。 (1)类(2)主题和(3)章。

课程包含各种课程名称,特定课程的主题包含不同的主题名称,而特定课程的章节包含不同的主题名称。

使用猫鼬,我可以获取/查找父母的章节集合,如下所示:

ChapterModel.find({})
  .limit(1)
  .populate([
    { path: "classId", model: ClassModel },
    { path: "subjectId", model: SubjectModel }
  ]);

给出以下结果:

[
  {
    "_id": "5de6a660a5f6a42060d532cd",
    "name": "Physical Quantities and Their Measurements",
    "subjectId": {
      "_id": "5de6a660a5f6a42060d532c5",
      "classId": "5de6a65fa5f6a42060d532c4",
      "name": "Physics"
    },
    "classId": {
      "_id": "5de6a65fa5f6a42060d532c4",
      "name": "IX"
    }
  }
]

但是我找不到以以下方式获取类子级的任何方法:

[
  {
    "_id" : ObjectId("5de6a660a5f6a42060d532c5"),
    "name": "IX",
    "subjects": [
      {
        "_id" : ObjectId("5de6a660a5f6a42060d532c6"),
        "name": "Physics",
        "classId": ObjectId("5de6a660a5f6a42060d532c5"),
        "chapters": [
          {
            "_id" : ObjectId('5c09fb04ff03a672a26fb23a'),
            "name": Physical Quantities and Their Measurements",
            "classId": ObjectId("5de6a660a5f6a42060d532c5"),
            "subjectId": ObjectId("5de6a660a5f6a42060d532c6"),
          },
          {
            "_id" : ObjectId("5de6a660a5f6a42060d532c6"),
            "name": "Motion",
            "classId": ObjectId("5de6a660a5f6a42060d532c5"),
            "subjectId": ObjectId("5de6a660a5f6a42060d532c6"),
          }
        ]
      }
    ]
  }
]

它们是否像填充所有嵌套子代或集合一样?

1 个答案:

答案 0 :(得分:1)

您可以使用猫鼬的populate功能。

解决问题的一种方法是设计如下的架构和模型: (请注意,因为它是javascript中的保留关键字,所以我使用课程名称而不是课程)

course.js

const mongoose = require("mongoose");

const courseSchema = new mongoose.Schema(
  {
    name: String
  },
  {
    toJSON: { virtuals: true }
  }
);

courseSchema.virtual("subjects", {
  ref: "Subject",
  foreignField: "course",
  localField: "_id"
});

module.exports = mongoose.model("Course", courseSchema);

subject.js

const mongoose = require("mongoose");

const subjectSchema = new mongoose.Schema(
  {
    name: String,
    course: {
      type: mongoose.Types.ObjectId,
      ref: "Course"
    }
  },
  {
    toJSON: { virtuals: true }
  }
);

subjectSchema.virtual("chapters", {
  ref: "Chapter",
  foreignField: "subject",
  localField: "_id"
});

module.exports = mongoose.model("Subject", subjectSchema);

chapter.js:

const mongoose = require("mongoose");

const chapterSchema = new mongoose.Schema({
  name: String,
  subject: {
    type: mongoose.Types.ObjectId,
    ref: "Subject"
  }
});

module.exports = mongoose.model("Chapter", chapterSchema);

请注意,虚拟关键字的意思是populate virtual。 我之所以选择这种解决方案,是因为否则我们应该在课程模式中保留一个称为主题的附加字段,我们需要在其中保留一组主题ID(以及主题模式中的Chapters字段)。

使用这些架构,您可以使用以下查询来获取所需的结果:

const Course = require("../models/course");

router.get("/courses", async (req, res) => {
  const result = await Course.find({}).populate({
    path: "subjects",
    populate: { path: "chapters" }
  });

  res.send(result);
});

如果您很难测试,以下是创建课程,主题和章节的其他途径:

const Subject = require("../models/subject");
const Chapter = require("../models/chapter");
const Course = require("../models/course");

router.post("/courses", async (req, res) => {
  const result = await Course.create(req.body);
  res.send(result);
});

router.post("/subjects", async (req, res) => {
  const result = await Subject.create(req.body);
  res.send(result);
});

router.post("/chapters", async (req, res) => {
  const result = await Chapter.create(req.body);
  res.send(result);
});

router.get("/courses", async (req, res) => {
  const result = await Course.find({}).populate({
    path: "subjects",
    populate: { path: "chapters" }
  });

  res.send(result);
});

首先,我用这个正文创建了一个帖子:(给出的课程ID为5de6c047856efe390cbf665d)

{
    "name": "IX"
}

然后,我使用此主体为5de6c047856efe390cbf665d的课程ID创建了一个主题:(给出了主体ID为5de6c0d7856efe390cbf665e)

{
    "name": "Physics",
    "course": "5de6c047856efe390cbf665d"
}

然后使用该主题ID 5de6c0d7856efe390cbf665e,我使用以下内容创建了两章:

{
    "name": "Physical Quantities and Their Measurements",
    "subject": "5de6c0d7856efe390cbf665e"
}
{
    "name": "Motion",
    "subject": "5de6c0d7856efe390cbf665e"
}

结果是:

[
    {
        "_id": "5de6c047856efe390cbf665d",
        "name": "IX",
        "__v": 0,
        "subjects": [
            {
                "_id": "5de6c0d7856efe390cbf665e",
                "name": "Physics",
                "course": "5de6c047856efe390cbf665d",
                "__v": 0,
                "chapters": [
                    {
                        "_id": "5de6c123856efe390cbf665f",
                        "name": "Physical Quantities and Their Measurements",
                        "subject": "5de6c0d7856efe390cbf665e",
                        "__v": 0
                    },
                    {
                        "_id": "5de6c136856efe390cbf6660",
                        "name": "Motion",
                        "subject": "5de6c0d7856efe390cbf665e",
                        "__v": 0
                    }
                ],
                "id": "5de6c0d7856efe390cbf665e"
            }
        ],
        "id": "5de6c047856efe390cbf665d"
    }
]