在 MongoDB 中查询和排序 many-to-many 关系
Query and Sort in MongoDB for a many-to-many relationship
假设我在users
、posts
、likes
之间有关系。一个用户可以点赞一个post,一个post可以被很多用户点赞。
我的目标是能够在 MongoDB 中设计一个数据库结构,这样我就可以快速查询用户喜欢的所有 post 并且 sort/filter 它们在多个下面列出的方式(不同时 - 考虑一个下拉菜单,让您更改搜索结果的排序顺序)
- post 被赞的顺序
- 按各种
post
属性进行过滤和排序 - 例如标题、post 回复的数量、post 的创建时间等
假设 post 的数量是 100,000 的数量级,每个 post 将有大约 100-1000 个赞
我想到的可能的解决方案:
1) likes
嵌入在 posts
中。
这使得#2 可以轻松处理,因为您只需要一个索引 likes.user_id
以及您需要的任何其他 post 属性。这也很快,因为您只需要 运行 一个查询。
但是,这使得无法按用户喜欢某事的时间进行排序 (AFAIK)。
2) likes
是一个单独的 collection,具有属性 post_id
、account_id
.
这样可以轻松处理#1,因为您只需按 _id 排序即可。但是,除非您将 post
属性复制并缓存到 like
文档中,否则无法处理 #2。这是可能的,但确实不理想。此外,这查询速度较慢。您需要 运行 两个查询 - 一个查询 like
collection,然后 post
使用 $in 的查询:[post_ids].
还有其他 solutions/designs 我应该考虑的吗?我是否遗漏了这些建议的解决方案中的任何内容?
我觉得你的第一个选项很好。它很好地处理了您的两个要求。
作为,
- 您需要根据 post 的属性对评论 post 进行排序,评论可以通过聚合
- 您需要根据某些属性过滤文档(posts),这也是可能的。
2 个集合的缺点是您需要 运行 2 个查询来获取一条数据。 NoSQL 数据库让您可以灵活地将相关数据存储在一个地方,并为此提供最佳性能。如果不使用 NoSQL 的优势,您将无法获得优化的性能。
不要从 RDBMS 的角度思考(忘记规范化)。如果您需要使用第一个选项进行更多性能优化,请使用索引、分片(使用分片键作为字母范围、地理等)
我会使用#2 的非规范化版本。有一个 like
文档:
{
"_id" : ObjectId(...),
"account_id" : 1234,
"post_id" : 4321,
"ts" : ISODate(...),
// additional info about post needed for basic display
"post_title" : "The 10 Worst-Kept Secrets of Cheesemongers"
// etc.
}
使用 { "account_id" : 1, "ts" : 1 }
上的索引,您可以高效地查找 like
特定用户的按喜欢时间排序的文档。
db.likes.find({ "account_id" : 1234 }).sort({ "ts" : -1 })
如果将 post 的基本信息放入 like
文档中,则无需检索 post 文档,直到用户单击某个link 显示整个 post。
权衡是,如果有关 post 的某些 like
嵌入信息发生变化,则需要在每个 like
中进行更改。这可能没什么,也可能很麻烦,具体取决于您选择嵌入的内容以及 post 获得很多赞后修改的频率。
假设我在users
、posts
、likes
之间有关系。一个用户可以点赞一个post,一个post可以被很多用户点赞。
我的目标是能够在 MongoDB 中设计一个数据库结构,这样我就可以快速查询用户喜欢的所有 post 并且 sort/filter 它们在多个下面列出的方式(不同时 - 考虑一个下拉菜单,让您更改搜索结果的排序顺序)
- post 被赞的顺序
- 按各种
post
属性进行过滤和排序 - 例如标题、post 回复的数量、post 的创建时间等
假设 post 的数量是 100,000 的数量级,每个 post 将有大约 100-1000 个赞
我想到的可能的解决方案:
1) likes
嵌入在 posts
中。
这使得#2 可以轻松处理,因为您只需要一个索引 likes.user_id
以及您需要的任何其他 post 属性。这也很快,因为您只需要 运行 一个查询。
但是,这使得无法按用户喜欢某事的时间进行排序 (AFAIK)。
2) likes
是一个单独的 collection,具有属性 post_id
、account_id
.
这样可以轻松处理#1,因为您只需按 _id 排序即可。但是,除非您将 post
属性复制并缓存到 like
文档中,否则无法处理 #2。这是可能的,但确实不理想。此外,这查询速度较慢。您需要 运行 两个查询 - 一个查询 like
collection,然后 post
使用 $in 的查询:[post_ids].
还有其他 solutions/designs 我应该考虑的吗?我是否遗漏了这些建议的解决方案中的任何内容?
我觉得你的第一个选项很好。它很好地处理了您的两个要求。 作为,
- 您需要根据 post 的属性对评论 post 进行排序,评论可以通过聚合
- 您需要根据某些属性过滤文档(posts),这也是可能的。
2 个集合的缺点是您需要 运行 2 个查询来获取一条数据。 NoSQL 数据库让您可以灵活地将相关数据存储在一个地方,并为此提供最佳性能。如果不使用 NoSQL 的优势,您将无法获得优化的性能。
不要从 RDBMS 的角度思考(忘记规范化)。如果您需要使用第一个选项进行更多性能优化,请使用索引、分片(使用分片键作为字母范围、地理等)
我会使用#2 的非规范化版本。有一个 like
文档:
{
"_id" : ObjectId(...),
"account_id" : 1234,
"post_id" : 4321,
"ts" : ISODate(...),
// additional info about post needed for basic display
"post_title" : "The 10 Worst-Kept Secrets of Cheesemongers"
// etc.
}
使用 { "account_id" : 1, "ts" : 1 }
上的索引,您可以高效地查找 like
特定用户的按喜欢时间排序的文档。
db.likes.find({ "account_id" : 1234 }).sort({ "ts" : -1 })
如果将 post 的基本信息放入 like
文档中,则无需检索 post 文档,直到用户单击某个link 显示整个 post。
权衡是,如果有关 post 的某些 like
嵌入信息发生变化,则需要在每个 like
中进行更改。这可能没什么,也可能很麻烦,具体取决于您选择嵌入的内容以及 post 获得很多赞后修改的频率。