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

时间:2017-12-16 05:21:16

标签: mongodb

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

User:
   _ _id
   - name
   - email

Company:
   - _id
   _ name
   _ slug

现在假设我需要将用户连接到公司。用户可以分配一个公司。为此,我可以在用户模型中添加一个名为companyID的新字段。但我不会将_id字段发送到前端。所有来到API的请求都只有slug。我有两种方法可以做到这一点:

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

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

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

2 个答案:

答案 0 :(得分:3)

第二种方法是最好的,即添加公司的_id。

使用_id是查询任何类型信息的最佳实践方式,甚至可以使用_id解决复杂查询,因为它是Mongodb创建的唯一ObjectId。填充是使用来自其他集合的文档自动替换文档中的指定路径的过程。我们可以填充单个文档,多个文档,普通对象,多个普通对象或从查询返回的所有对象。

答案 1 :(得分:3)

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

  1. 该字段必须是唯一的。我不确定' slug'架构中的字段代表,但如果有可能重复,则不要使用它。
  2. 该字段不得更改。严格地说,你可以更改一个关键字段,但安全这样做的唯一方法是同时在所有子表中原子地更改它。这是一件难以可靠的事情,因为a)你必须知道哪些表正在使用该字段(也许其他一些开发人员添加了另一个你不知道的表)b)如果你一次只做一个,您将介绍竞争条件c)如果任何更新失败,您将拥有不一致的数据和损坏的父子链接。有些SQL DB有一个级联更新功能来解决这个问题,但是Mongo没有。这是一个非常困难的问题,如果你不必要,你真的,真的不想改变一个关键领域。
  3. 必须对该字段编制索引。严格来说,这不是真的,但是如果您要加入它,那么您将对其进行大量查询,因此您需要对其进行索引。
  4. 由于这些原因,几乎总是建议使用仅将 作为关键字段的关键字段,而不存储实际信息。许多人使用诸如社会安全号码,驾驶执照等等作为关键领域被烧毁,或者因为可能存在重复(例如,如果人们使用假数字,或者如果他们没有,则可以复制SSN)一),或数字可以改变(例如驾驶执照)。

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

    最重要的是,有充分的理由不使用"真正的"如果你可以提供帮助,那么你可以使用田地。幸运的是,mongoDB已经为您提供了一个很好的关键字段,它满足上述所有条件,即_id字段。因此,你应该使用它。即使slu is不是真正的"字段,你生成它与_id字段完全相同,为什么这么麻烦?为什么记录必须有2个唯一标识符?

    在您的情况下,第二个问题是您不会将公司的_id字段暴露给用户。直观地说,似乎这应该是一个有价值的信息,不应该毫不客气地发出。但事实是,它本身没有信息价值,因为如上所述,密钥应该没有实际信息。实现安全性的地方在查询中,确保执行查询的用户有权访问她要求的记录/特定字段。隐藏密钥是一种经典的安全隐患,实际上并没有提高安全性。

    隐藏主键的唯一方法是,如果您使用 包含有用信息的经过深思熟虑的密钥。例如,某人可以使用每张发票增加1的发票ID来确定您每天获得的订单数量。也可以很容易地猜到自动增量ID(如果我的发票是#5,我可以窥探发票#6吗?)。幸运的是,Mongo使用UUID,因此确实没有信息泄露(除了可能对其加密算法进行定时攻击?如果你担心这一点,你需要比这篇帖子更深入的安全考虑因素) : - 。)

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

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

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