简体   繁体   中英

MongoDB - not in other table (many-to-many relationship)

I'm learning to use mongodb. I made 3 collections (User, Enrollment, Courses)

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"   |
+---------+----------+

Everytime user click on one of the courses will added into enrollment table. I am able to show the enrolled list for user, but I have no idea how to show courses that have not been enrolled by user.

I would like to know how to show courses that have not been added to enrollment table by user? I tried to use user_id: { $ne: 1 } , but doesn't seem show the correct courses that have not been enrolled.

How to show correctly?

You can use aggregation

Assuming you know user_id , let's say we choose Bob with user_id: 2

You can either start with getting all courses from Course and filter only courses that the user has not enrolled

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

Or start with Enrollment from a particular User and find the courses from 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

Note that above approaches don't have the same output structure, you will have to manipulate the to get to your desired output shape.

With this collection structure:

Step 1 : Fetch user's enrolled courses list. For eg: user 2's courses: ['2222']

Step 2 : Use find query ( { courseID: { $nin: ['2222'] } } ) on Courses collection to fetch un-enrolled courses list.

However, I'd suggest you to update collection's schema by either of following ways:

  • Save enrolled courses Ids in User collection in an Array.
  • Save Courses in an Array in Enrollment collection.

This way, you can eliminate some processing in Step 1.

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM