我在MongoDB中有很多关系实现的特定问题。
我收集了歌曲和艺术家(百万文档)。这首歌可以唱 许多艺术家和艺术家都可以唱很多歌。所以我跟着了 两个集合中的文档引用方法。像这样...
1。 歌曲 收藏: -
{
_id:ObjectId("dge547567hheheasfw3454dfg"),
title:"xyz",
artists:[ObjectId("xfvdg464654"), ...] //many artists // artists ids
}
2。 艺术家 收藏品: -
{
_id:ObjectId("dge547567hheheasfw3454dfg"),
title:"xyz",
songs:[ObjectId("xfvdg464654"), ...] //many songs // songs Ids
}
但问题是在对一个集合进行CRUD操作时我必须对其他集合进行CRUD操作。就像删除艺术家一样,我必须在歌曲的所有文档中删除艺术家阵列中的艺术家。有一个艺术家。这可能导致 原子性问题。 如何确保原子性?
其次,当数据库增长并且歌曲由艺术家演唱时 将增加因此文件增长的收集和文件大小可以达到16MB或更高(MAX DOC SIZE)。
那么在这种情况下可以做些什么呢?
答案 0 :(得分:5)
让我们首先详细说明您的案例的多对多关系,并尝试了解可以做什么和不可做什么 -
一首歌可以由多达10位或20位艺术家演唱(假设它不是那么复杂/多样化,可能需要100位艺术家)。
在这种情况下,songs
集合中的分段艺术家ID很完美,我们可以安全地假设即使在最糟糕的情况下(存储由100位艺术家演唱的复杂/多样化的歌曲)它永远不会强制我们的歌曲收集超过16 MB。
然而,一位艺术家可能会在他的职业生涯中唱出多达1000首歌曲或更多歌曲。一个12字节长的ObjectId,在这种情况下,将一个集合增长到仅12000字节的大小,这比16000000字节小。你仍然留有很大的空间。因此无需担心达到16MB的上限。
方法 - 1
inter-bucketing对于期望高读取的关系非常有效。
一些艺术家的歌曲可以在单个查询中获取,反之亦然。在这两个系列中,索引会更加顺畅。
但是如果我们围绕艺术家里面的歌曲和歌曲中的艺术家,那么我们的更新不再是Atomic,但为此,我们仍然可以为艺术家和歌曲CRUD实现应用程序级别两阶段提交,即使是有点麻烦,解决问题。
方法 - 2:
为什么不在歌曲集合里面只播放艺术家id并拥有 该领域的多键索引。
唱歌的艺术家名单太短,而不是艺术家演唱的歌曲列表。所以我们只在歌曲收藏中装载艺术家。
这样我们就会 -
1。如果我们在艺术家收藏中发布了多曲的歌曲,那就避免几乎不可能达到艺术家收藏的最大尺寸。
2。避免为至少songs
个集合编写2P提交。所有关系读取只能通过歌曲收集来满足(这里我不包括艺术家的_id查找)
3。即使在对艺术家演唱的歌曲的歌曲集合进行反向查询时,也只需一次查询即可确保快速访问数据。
您已经拥有了一些您需要获取歌曲的艺术家信息(_id)。你只需起草一个这样的查询 -
db.songs.find({ artists: 'your-artist-id' });
当你解释这个问题时,当你意识到它利用你的多键索引时,你会发现快乐。那里很棒!
现在采用哪种方法?
我发现第二种方法对于您的用例更为微妙,因为它降低了管理2P提交原子性的一些复杂性,并且仍然提供了良好的读取性能。第一种方法绝对是面向读取的,所以如果你确定你将收到很多很多关于这两个集合的读取,那就去找第一个,否则第二个就应该做。
答案 1 :(得分:2)
我通过采用与我们在sql中所做的类似的第三个集合在mongodb中实现了多对多的关系。
歌曲收藏
{
_id:ObjectId("dge547567hheheasfw3454df12"),
title:"xyz",
length : 123
}
艺术家合集
{
_id:ObjectId("dge547567hheheasfw3454d32"),
name:"abc",
}
SongArtist Collection
{
_id:ObjectId("dge547567hheheasdfsdfsdfgdfga42"),
artist: ObjectId("dge547567hheheasfw3454dfg32"),
song: ObjectId("dge547567hheheasfw3454df12"),
}