要在MongoDB中将一条记录与另一条记录联系起来,是否可以使用slug?

THp*_*ubs 5 mongodb

假设我们有两个这样的模型:

User:
   _ _id
   - name
   - email

Company:
   - _id
   _ name
   _ slug
Run Code Online (Sandbox Code Playgroud)

现在让我们说我需要将用户连接到公司.用户可以分配一个公司.为此,我可以添加companyID在用户模型中调用的新字段.但我不是把_id球场送到前端.所有来到API的请求都将是slug唯一的.我有两种方法可以做到这一点:

1)添加slug以关联公司:如果我这样做,我可以从请求发送的slug并直接查询公司.

2)添加_id公司:如果我这样做,我需要首先使用slug查询公司,然后使用_id返回查询所需的数据.

我可以知道哪种方式最好吗?使用_id关系记录时是否有额外的好处?

Has*_*cut 3

同意第二种方法。在决定使用哪个字段作为连接键时需要考虑几个问题(所有数据库都是如此,而不仅仅是 Mongo):

  1. 该字段必须是唯一的。我不确定模式中的“slug”字段到底代表什么,但如果有任何可能重复的机会,那么就不要使用它。
  2. 该字段不得更改。严格来说,您可以更改关键字段,但安全地执行此操作的唯一方法是同时在所有子表中原子地更改它。这是一件很难可靠地完成的事情,因为a)您必须知道哪些表正在使用该字段(也许其他开发人员添加了您不知道的另一个表)b)如果您一次执行一个,那么您'将引入竞争条件 c) 如果任何更新失败,您将获得不一致的数据和损坏的父子链接。一些 SQL DB 有级联更新功能来解决这个问题,但 Mongo 没有。这是一个足够困难的问题,如果没有必要,您真的非常不想更改关键字段。
  3. 该字段必须建立索引。严格来说,这是不正确的,但如果您要加入它,那么您将对其运行大量查询,因此您需要对其建立索引。

由于这些原因,几乎总是建议使用仅用作关键字段的关键字段,其中不存储任何实际信息。很多人都因为使用社会安全号码、驾驶执照等作为关键字段而被烧伤,这要么是因为可能存在重复(例如,如果人们使用假号码,或者如果他们没有号码,SSN 可能会重复) ,或者数字可能会改变(例如驾驶执照)。

另外,通过这样做,您可以格式化关键字段以优化唯一生成和索引的速度。例如,如果您使用 SSN,则需要根据数据库的其余部分检查 SSN 以确保其唯一。如果您有数百万条记录,这需要时间。对于 slugs 也是如此,它们是需要进行哈希处理并根据索引进行检查的文本字段。OTOH,mongoDB 本质上使用 UUID 作为键,这意味着它不必检查唯一性(该算法保证唯一性的高统计可能性)。

最重要的是,如果可以的话,有充分的理由不使用“真实”字段作为密钥。幸运的是,mongoDB 已经为您提供了一个满足上述所有条件的重要字段,即 _id 字段。因此,您应该使用它。即使 slug 不是一个“真正的”字段,并且您生成它的方式与 _id 字段完全相同,为什么还要麻烦呢?为什么一条记录必须有 2 个唯一标识符?

您的情况的第二个问题是您没有向用户公开公司的 _id 字段。直觉上,这似乎应该是一条有价值的信息,不应该随意泄露。但事实是,它本身没有信息价值,因为如上所述,密钥不应该有实际信息。实现安全性的地方是在查询中,确保执行查询的用户有权访问她所请求的记录/特定字段。隐藏密钥是一种经典的隐藏式安全方法,实际上并不能提高安全性。

隐藏主键的唯一时机是,如果您使用的键未经深思熟虑,但确实包含有用信息。例如,某人可以使用每张发票加 1 的发票 ID 来计算您一天收到的订单数量。自动增量 ID 也很容易被猜到(如果我的发票是 #5,我可以窥探发票 #6 吗?)。幸运的是,Mongo 使用 UUID,因此实际上不会泄露任何信息(除了对其加密算法的定时攻击?如果您担心这一点,那么您需要比这篇文章更深入的安全考虑:-)。

从另一个角度来看:如果 slug 可靠地指向特定公司和用户,那么它如何比仅使用 _id 更安全?

也就是说,在某些情况下,公开辅助密钥(如 slugs)是有帮助的,但这些都与安全性无关。例如,如果将来您需要迁移数据库平台并需要重新生成密钥,因为新平台无法使用您的旧平台;或者,如果用户将手动输入标识符,那么为他们提供一些更容易记住的东西(例如slugs)会很有帮助。但即使在这些情况下,您也可以使用 slug 作为方便用户使用的标识符,但在您的数据库中,您仍然应该使用公司 ID 来执行实际的连接(如选项#2 中所示)。查看有关向用户公开 _ids 的优点/缺点的讨论: https://softwareengineering.stackexchange.com/questions/218306/why-not-expose-a-primary-key

因此,我的建议是继续为用户提供公司 ID(如果您想要人类可读的格式(例如 URL,尽管 mongo _ids 可以在 URL 中使用),则还需要提供 slug)。他们可以将其发送回给您以获取用户,并且您可以(在适当的权限检查后)进行加入并发送回用户数据。如果您不想公开公司 ID,那么我建议您使用选项#2,这本质上是相同的,只是您要添加一个额外的查询来首先获取公司 ID。恕我直言,这浪费了周期,没有真正提高安全性,但如果有其他考虑,那么它仍然是可以接受的。这两个选项都比使用 slug 作为主键更好。