【问题标题】:RethinkDB: Outer Join from Table to ArrayRethinkDB:​​从表到数组的外部连接
【发布时间】:2017-03-17 18:58:10
【问题描述】:

我有三个表、类、课程和 userSchedules,如下所示:

课程 { "classId": "24ab7b14-f935-44c1-b91b-8598123ea54a", "courseNumber": "PO101" , "days": "MWF" , "professor": "Abramius Darksbayn" , "seatsAvailable": 23 , "time": 11 }

课程 { "courseNumber": "PO101" , "courseName": "Intro to Potions" , "creditHours": 3 , "description": "Potions..." }

用户计划 { "userId": "123", "classes": [ "24ab7b14-f935-44c1-b91b-8598123ea54a", "ab7b4414-a833-4ac2-c84a-98123ea54a97" ] , }

我想编写一个查询来连接课程和课程(在 courseNumber 上),然后外连接到 userSchedules。因此,我想始终返回所有课程及其相应的课程,并且如果用户注册了该课程,我想返回。所以我希望结果看起来像这样:

{ "classId": "24ab7b14-f935-44c1-b91b-8598123ea54a", "days": "MWF" , "professor": "Abramius Darksbayn" , "seatsAvailable": 23 , "time": 11, "course": { "courseNumber": "PO101" , "courseName": "Intro to Potions" , "creditHours": 3 , "description": "Potions..." }, isEnrolled: true }

我真的很难弄清楚如何使这项工作完全发挥作用,其次,最高效的方法是做到这一点。任何帮助将不胜感激!谢谢!

编辑 好的,我找到了一种方法来完成大部分工作,但看起来确实有很多代码,我也想知道它的性能。 而且!!result("right") 总是返回true,即使外部连接没有“右侧”。有没有更好的方法来做到这一点:

r.table('classes') .eqJoin('courseNumber', r.table('courses')) .outerJoin( r.table('userSchedules').getAll(userId).concatMap(schedule => schedule('classes')), (joinedClass, scheduledClassId) => joinedClass('left')('classId').eq(scheduledClassId)) .map(result => { return { classId: result('left')('left')('classId'), days: result('left')('left')('days'), professor: result('left')('left')('professor'), seatsAvailable: result('left')('left')('seatsAvailable'), time: result('left')('left')('time'), course: result('left')('right'), enrolled: result.hasFields('right') } })

编辑 2: 我弄清楚了为什么 isEnrolled 不起作用。我已经编辑了上面的查询来展示我最近的努力。

【问题讨论】:

    标签: rethinkdb rethinkdb-javascript


    【解决方案1】:

    如果您只想让您的查询更具可读性,您可以将其更改为这个:

    const allUserClasses = 
              r.table('userSchedules')
               .getAll(userId)
               .concatMap(schedule => schedule('classes'))
    
    r.table('classes')
      .eqJoin('courseNumber', r.table('courses'))
      .map(joined => joined('left').without('courseNumber').merge({course: joined('right') })
      .outerJoin(allUserClasses,
        (joinedClass, scheduledClassId) => joinedClass('classId').eq(scheduledClassId))
      .map(result => result('left').merge({ enrolled: result.hasFields('right') })
    

    另外,如果你有一个固定的小数组,外连接总是过大的,这更合适:

    r.table('userSchedules')
     .get(userId)('classes')
     .do(userClasses =>
        r.table('classes')
         .eqJoin('courseNumber', r.table('courses'))
         .map(joined => joined('left')
             .without('courseNumber')
             .merge({
                course: joined('right'),
                enrolled: userClasses.contains(joined('left')('classId')) 
             })
         )
     )
    

    【讨论】:

    • 我还有另一个挑战使这个查询变得非常复杂。我现在想获取每个班级的学生人数。对于每个类,这将是在其 userSchedules.classes 数组中具有该 classId 的用户数。挑战在于这将是一个聚合,但我仍然需要知道当前用户是否已注册。有没有办法在不进行 2 次查询的情况下做到这一点?为了让它更具挑战性,我想听听这些变化,以便实时更新班级的可用座位数。
    • 也许此时我应该停止使用数组来使连接更容易和/或更高效?
    • 这将使查询变得更加复杂,因为连接上没有变化源。有几种方法。一种方法是创建一个“物化视图”表,该表将包含您想要的所有信息,您将使用侦听器填充它以更改来自其他表的提要,这可能有点昂贵。另一种方法是通过前一个查询的无限光标在迭代内部进行查询,但这有点过于复杂,无法在评论中显示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 2022-08-11
    相关资源
    最近更新 更多