如何处理mongoDB中的多对多关系?

时间:2018-04-07 19:12:18

标签: mongodb mongoose schema entity-relationship

我在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)。

那么在这种情况下可以做些什么呢?

2 个答案:

答案 0 :(得分:5)

让我们首先详细说明您的案例的多对多关系,并尝试了解可以做什么和不可做什么 -

  • 一首歌可以由多达10位或20位艺术家演唱(假设它不是那么复杂/多样化,可能需要100位艺术家)。

    在这种情况下,songs集合中的分段艺术家ID很完美,我们可以安全地假设即使在最糟糕的情况下(存储由100位艺术家演唱的复杂/多样化的歌曲)

  • 然而,一位艺术家可能会在他的职业生涯中唱出多达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"),
}
  • 现在,当您进行crud操作并且想要从歌曲中删除艺术家时 你可以在SongArtist Collection中的单个查询中完成。
  • 超出文档大小永远不会有任何问题
  • 如果您想要删除特定歌曲中的特定歌曲 查询一次
  • 它会增加集合中的记录数量,但是mongodb可以很容易地处理它。
  • 您可以在单个查询中找到与一位艺术家相关的所有歌曲,反之亦然。