在数据库中实现 [user — subscriptions/subscribers] 关系的最佳方式

Best way to implement [user — subscriptions/subscribers] relation in database

我正在使用 Swift 4 + Vapor 框架、Fluent ORM 和 PostgreSQL 作为驱动程序编写服务器。我有一个用户模型,它应该有订阅者和订阅(也是用户模型)。我在这里有两个选择:1. 存储具有唯一 ID 的数组 subscriptions/subscribers 或 2. 建立一对多的用户-用户关系。您认为哪个更好,我该如何实施?

存储数组不是最优的。查询您的数据库以查找用户的所有订阅者将需要解析每个用户的订阅数组并找到包含您的目标用户 ID 的那些。关系是一个更好的主意。

Fluent 使用 Pivot class 来模拟多对多关系。因为它是自引用关系,为避免 ID 键冲突,您可能会发现创建自己的 'through' 模型最简单。

import FluentProvider
import Vapor

final class Subscription: Model, PivotProtocol {

  typealias Left = User
  typealias Right = User

  var subscriberId: Identifier
  var subscribedId: Identifier

  init(
    subscriberId: Identifier,
    subscribedId: Identifier
  ) {
    self.subscriberId = subscriberId
    self.subscribedId = subscribedId
  }

  let storage = Storage()

  static let leftIdKey = "subscriber_id"
  static let rightIdKey = "subscribed_id"

  init(row: Row) throws {
    subscriberId = try row.get("subscriber_id")
    subscribedId = try row.get("subscribed_id")
  }

  func makeRow() throws -> Row {
    var row = Row()
    try row.set("subscriber_id", subscriberId)
    try row.set("subscribed_id", subscribedId)
    return row
  }

}

extension User {
  var subscribers: Siblings<User, User, Subscription> {
    return siblings(localIdKey: "subscriber_id", foreignIdKey: "subscribed_id")
  }
  var subscribed: Siblings<User, User, Subscription> {
    return siblings(localIdKey: "subscribed_id", foreignIdKey: "subscriber_id")
  }
}