【问题标题】:MongoDB - not in other table (many-to-many relationship)MongoDB - 不在其他表中(多对多关系)
【发布时间】:2020-06-30 12:35:30
【问题描述】:

我正在学习使用 mongodb。我做了 3 个集合(用户、注册、课程)

User
+--------------------------------------+---------+--------+
| _id                                  | user_id | name   |
+--------------------------------------+---------+--------+
| ObjectId("5ee6c0511d0843811413b225") | 1       | John   |
+--------------------------------------+---------+--------+
| ObjectId("5ef9e9b11db598099e183319") | 2       | Bob    |
+--------------------------------------+---------+--------+

Courses
+--------------------------------------+---------+-----------------+
| _id                                  | courseID| courseName      |
+--------------------------------------+---------+-----------------+
| ObjectId("5ef9d1b28e08e1c04ac9530b") | "1111"  | English         |
+--------------------------------------+---------+-----------------+
| ObjectId("5ef9db2bdd883a3444dd396a") | "2222"  | Algebra 1       |
+--------------------------------------+---------+-----------------+
| ObjectId("5ef9ea212c72182edf809a52") | "3333"  | World History   |
+--------------------------------------+---------+-----------------+
| ObjectId("5ee6c0511d0843811413b226") | "4444"  | Algebra 2       |
+--------------------------------------+---------+-----------------+

Enrollment
+---------+----------+
| user_id | courseID |
+---------+----------+
| 1       | "1111"   |
+---------+----------+
| 2       | "2222"   |
+---------+----------+
| 1       | "2222"   |
+---------+----------+
| 1       | "4444"   |
+---------+----------+

每次用户点击其中一门课程都会添加到招生表中。 我可以为用户显示已注册的列表,但我不知道如何显示用户尚未注册的课程。

我想知道如何显示尚未被用户添加到注册表中的课程? 我尝试使用user_id: { $ne: 1 },但似乎没有显示正确的尚未注册的课程。

如何正确显示?

【问题讨论】:

    标签: mongodb


    【解决方案1】:

    您可以使用aggregation

    假设您知道 user_id,假设我们选择 Bob 和 user_id: 2

    您可以先从 Course 获取所有课程,然后只过滤用户未注册的课程

    db.Course.aggregate({
      $lookup: { // "join" with Enrollment
        from: "Enrollment",
        localField: "courseID",
        foreignField: "courseID",
        as: "enrollments"
      },
    },
    {
      $match: { // only match courses that user_id 2 doesn't exist in list of enrolments
        "enrollments.user_id": {
          $ne: 2
        }
      }
    })
    

    Playground

    或从特定User 中的Enrollment 开始,然后从Course 中查找课程

    db.Enrollment.aggregate({
      $match: { // find enrolments of user_id 2
        user_id: 2
      }
    },
    {
      $group: { // combine all courseID into an array
        _id: "$user_id",
        courseIDs: {
          $push: "$courseID"
        }
      }
    },
    {
      $lookup: { // "join" with Course that is not in the list of enrolments
        from: "Course",
        as: "notEnrolledCourses",
        let: {
          courseIDs: "$courseIDs"
        },
        pipeline: [
          {
            $match: {
              $expr: {
                $not: {
                  $in: [
                    "$courseID",
                    "$$courseIDs"
                  ]
                }
              }
            }
          }
        ]
      }
    })
    

    Playground

    请注意,上述方法没有相同的输出结构,您必须对其进行操作才能获得所需的输出形状。

    【讨论】:

    • 谢谢伙计。我做了类似的事情,但返回的是这样的对象<pymongo.command_cursor.CommandCursor object at 0x00000213EFE629A0> 如何在模板上显示它,比如烧瓶?
    • 你使用哪个库来连接数据库?
    • @thamsada.ts 我正在使用 flask_mongoengine
    • 我对python不太熟悉,但由于它返回一个游标,我认为你必须用list()包装它
    • @thamsada.ts 谢谢我已经做到了。再次感谢
    【解决方案2】:

    使用这种集合结构:

    第 1 步:获取用户的已注册课程列表。例如:用户 2 的课程:['2222']

    第 2 步:在 Courses 集合上使用 find 查询 ({ courseID: { $nin: ['2222'] } }) 以获取未注册的课程列表。

    但是,我建议您通过以下任一方式更新集合的架构:

    • User 集合中的已注册课程 ID 保存在一个数组中。
    • 将课程保存在 Enrollment 集合中的数组中。

    这样就可以省去步骤一中的一些处理。

    希望这会有所帮助!

    【讨论】:

    • @Abishek 你是这个意思吗? UserCollection: user_id(int), name(string), enrolled[]enrollmentCollection: courseID(int), courseName(string), users[]
    • @sekti92uk 如果您在Enrollment 中没有额外的数据,例如startDate,使用上述结构比您在问题中的结构更有利。您只需要将数组保留在一侧,所以enrolled[]users[]
    • @sekti92uk 是的,我的意思只是这样。将已注册的数组保存在 UserCollection 中。如果你这样做并且没有任何额外的字段EnrolledCollection。然后你可以删除Enrolled收藏。
    猜你喜欢
    • 2019-03-20
    • 2021-05-15
    • 1970-01-01
    • 2013-01-02
    • 2018-11-03
    • 1970-01-01
    • 2019-09-04
    • 2020-12-05
    • 1970-01-01
    相关资源
    最近更新 更多