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

问题描述 投票:5回答:2

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

User:
   _ _id
   - name
   - email

Company:
   - _id
   _ name
   _ slug

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

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

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

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

mongodb
2个回答
3
投票

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

  1. 该字段必须是唯一的。我不确定模式中的'slug'字段到底是什么,但是如果有可能重复,那么就不要使用它。
  2. 该领域不得改变。严格地说,您可以更改关键字段,但安全地这样做的唯一方法是同时在所有子表中以原子方式更改它。这是一件难以可靠的事情,因为a)你必须知道哪些表正在使用该字段(也许其他一些开发人员添加了另一个你不知道的表)b)如果你一次只做一个,那么你' ll引入竞争条件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更安全?

也就是说,在某些情况下,暴露二级密钥(如slu)是有帮助的,其中没有一个与安全性有关。例如,如果将来您需要迁移数据库平台并需要重新生成密钥,因为新平台无法使用旧平台;或者如果用户将手动输入标识符,那么给他们提供像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作为主键更好。


3
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.