【问题标题】:Fetch/Find child collection using mongoose使用猫鼬获取/查找子集合
【发布时间】:2020-03-28 12:25:34
【问题描述】:

我是 MongoDB 的新手。我对嵌套集合有一些问题。假设我在 mongodb 中有 3 个不同的集合。 (1) 课程 (2) 科目和 (3) 章节。

类包含不同的类名称,主题包含特定类的不同主题名称,章节包含特定主题的不同主题名称。

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

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"),
          }
        ]
      }
    ]
  }
]

他们是否有类似填充的方式来查找所有嵌套的子项或集合?

【问题讨论】:

    标签: node.js mongodb mongoose


    【解决方案1】:

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

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

    课程.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);
    

    主题.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);
    

    章节.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);
    

    请注意,virtual 关键字表示populate virtual。 我选择了这个解决方案,因为否则我们应该在课程模式中保留一个名为 subject 的附加字段,我们需要在其中保留一个主题 ID 数组(以及主题模式中的章节字段)。

    使用这些架构,您可以使用以下查询来获得您想要的结果:

    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"
        }
    ]
    

    【讨论】:

    • 为什么会生成一个额外的 id 字段?
    • @RejaulKarim id值和_id是一样的值,好像是因为toJSON的缘故。但我认为这不是一个大问题。我稍后会在这里评论以删除该 _id。
    • @RejaulKarim 在架构定义中添加 id: false 选项,如下所示:{ toJSON: { virtuals: true }, id: false }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 2013-04-16
    • 1970-01-01
    • 2018-03-19
    • 2021-09-03
    • 2018-12-20
    相关资源
    最近更新 更多