在非关系数据库中存储喜欢
Storing Likes in a Non-Relational Database
要点
我在我的应用程序中实现了一个赞按钮。假设用户能够喜欢其他用户的产品。
问题
我现在想知道以下哪种方法是将这些点赞存储在非关系数据库中的最有效和最可靠的方法(在我的例子中 MongoDB)。重要的是,任何用户都不能对一个产品点赞两次。
可能的解决方案
(1) 存储那些喜欢产品本身的用户 ID,并通过 likes.length
跟踪喜欢的数量
// Product in database
{
likes: [
'userId1',
'userId2',
'userId3',
...
],
...
}
(2) 存储用户自己喜欢的所有产品,并通过产品上的数字跟踪喜欢的数量
// User in database
{
likedProducts: [
'productId1',
'productId2',
'productId3',
...
]
...
}
// Product in database
{
numberOfLikes: 42,
...
}
(3) 也许有更好的解决方案?
无论哪种方式,如果产品有很多喜欢或者用户喜欢很多产品,就会有大量数据,只需要加载来显示喜欢并检查用户是否已经喜欢它。
使用哪种方法,(1) 或 (2) 取决于您的用例,具体而言,您应该考虑需要更多访问哪些数据:检索特定用户喜欢的所有产品 (2)或检索所有喜欢特定产品的用户 (1)。看起来更有可能 (1) 是更常见的情况 - 这样您就可以很容易地知道用户是否已经喜欢该产品以及产品的喜欢次数,因为它只是数组长度。
我认为任何进一步的改进都可能是过早的优化 - 最好针对手头的问题进行优化。
例如,如果显示喜欢的数量似乎是一个瓶颈,您可以通过将数组长度存储为单独的键值来进一步对数据进行非规范化。这样显示产品列表不需要从数据库中接收带有 userIds 的点赞数组。
更不可能的是,如果单个产品有数百万个赞,您会发现循环遍历 likes 数组以检查 userId 是否已在其中会显着降低速度。当然,您可以使用 sorted array 之类的东西来保持排序,但数据库通信仍然很慢(无论如何都比在内存中循环数组慢)。最好使用数据库索引进行二进制搜索,而不是将喜欢的数组存储为嵌入到产品(或用户)中的数组,您可以将喜欢存储在单独的集合中:
{
_id: $oid1,
productId: $oid2,
userId: $oid3
}
如果所有 3 个键都已编入索引,那么假设产品具有包含多个点赞的键,这应该是访问点赞的最快方式。
您也可以发挥创意,使用 $oid2+$oid3 的连接作为 $oid1,这将自动强制用户-产品对 likes 的唯一性。因此,您只需尝试保存它并忽略数据库错误(可能会导致细微的错误,因此在保存失败时检查 like exists 会更安全)。
为什么不修改需求并使用关系数据库或 RDBMS 类似的解决方案。基本上,使用正确的工具来完成正确的工作:
创建另一个 table 点赞,将您的 productId 和 userId 对作为唯一键。例如:
userId1 - productId2
userId2 - productId3
userId2 - productId2
userId1 - productId5
userId3 - productId2
然后您可以通过 userId 查询并获取每个用户的点赞数,或者通过 productId 查询并获取每个产品的点赞数。
此外,唯一键userId_productId将保证一个用户只能喜欢一个产品。
此外,您可以在另一列中保留额外的信息,例如用户喜欢该产品的时间戳等。
您可能还需要考虑文档大小、在每个产品上存储用户 ID 或在每个用户中存储字符串产品 ID 可能会导致内存中断并且无法很好地扩展。
Rdbms 将是解决此问题的更好方法。
要点
我在我的应用程序中实现了一个赞按钮。假设用户能够喜欢其他用户的产品。
问题
我现在想知道以下哪种方法是将这些点赞存储在非关系数据库中的最有效和最可靠的方法(在我的例子中 MongoDB)。重要的是,任何用户都不能对一个产品点赞两次。
可能的解决方案
(1) 存储那些喜欢产品本身的用户 ID,并通过 likes.length
// Product in database
{
likes: [
'userId1',
'userId2',
'userId3',
...
],
...
}
(2) 存储用户自己喜欢的所有产品,并通过产品上的数字跟踪喜欢的数量
// User in database
{
likedProducts: [
'productId1',
'productId2',
'productId3',
...
]
...
}
// Product in database
{
numberOfLikes: 42,
...
}
(3) 也许有更好的解决方案?
无论哪种方式,如果产品有很多喜欢或者用户喜欢很多产品,就会有大量数据,只需要加载来显示喜欢并检查用户是否已经喜欢它。
使用哪种方法,(1) 或 (2) 取决于您的用例,具体而言,您应该考虑需要更多访问哪些数据:检索特定用户喜欢的所有产品 (2)或检索所有喜欢特定产品的用户 (1)。看起来更有可能 (1) 是更常见的情况 - 这样您就可以很容易地知道用户是否已经喜欢该产品以及产品的喜欢次数,因为它只是数组长度。
我认为任何进一步的改进都可能是过早的优化 - 最好针对手头的问题进行优化。
例如,如果显示喜欢的数量似乎是一个瓶颈,您可以通过将数组长度存储为单独的键值来进一步对数据进行非规范化。这样显示产品列表不需要从数据库中接收带有 userIds 的点赞数组。
更不可能的是,如果单个产品有数百万个赞,您会发现循环遍历 likes 数组以检查 userId 是否已在其中会显着降低速度。当然,您可以使用 sorted array 之类的东西来保持排序,但数据库通信仍然很慢(无论如何都比在内存中循环数组慢)。最好使用数据库索引进行二进制搜索,而不是将喜欢的数组存储为嵌入到产品(或用户)中的数组,您可以将喜欢存储在单独的集合中:
{
_id: $oid1,
productId: $oid2,
userId: $oid3
}
如果所有 3 个键都已编入索引,那么假设产品具有包含多个点赞的键,这应该是访问点赞的最快方式。
您也可以发挥创意,使用 $oid2+$oid3 的连接作为 $oid1,这将自动强制用户-产品对 likes 的唯一性。因此,您只需尝试保存它并忽略数据库错误(可能会导致细微的错误,因此在保存失败时检查 like exists 会更安全)。
为什么不修改需求并使用关系数据库或 RDBMS 类似的解决方案。基本上,使用正确的工具来完成正确的工作:
创建另一个 table 点赞,将您的 productId 和 userId 对作为唯一键。例如:
userId1 - productId2
userId2 - productId3
userId2 - productId2
userId1 - productId5
userId3 - productId2
然后您可以通过 userId 查询并获取每个用户的点赞数,或者通过 productId 查询并获取每个产品的点赞数。
此外,唯一键userId_productId将保证一个用户只能喜欢一个产品。
此外,您可以在另一列中保留额外的信息,例如用户喜欢该产品的时间戳等。
您可能还需要考虑文档大小、在每个产品上存储用户 ID 或在每个用户中存储字符串产品 ID 可能会导致内存中断并且无法很好地扩展。 Rdbms 将是解决此问题的更好方法。