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

Abh*_*ngh 8 schema entity-relationship mongoose mongodb

我在MongoDB中有很多关系实现的特定问题.

我有歌曲艺术家的集合(百万文档).歌曲可以由多位艺术家演唱,艺术家可以唱很多歌.所以我在两个集合中都遵循了文档引用的方法.像这样...

1. 歌曲收藏: -

{
  _id:ObjectId("dge547567hheheasfw3454dfg"),
   title:"xyz",
   artists:[ObjectId("xfvdg464654"), ...] //many artists // artists ids
}
Run Code Online (Sandbox Code Playgroud)

2. 艺术家收藏: -

{
  _id:ObjectId("dge547567hheheasfw3454dfg"),
   title:"xyz",
   songs:[ObjectId("xfvdg464654"), ...] //many songs // songs Ids 
}
Run Code Online (Sandbox Code Playgroud)

但这里的问题是在对一个集合进行CRUD操作时,我必须对其他集合进行CRUD操作.就像删除艺术家一样,我必须在艺术家的歌曲的所有文档中删除艺术家阵列中的艺术家.这可能会导致原子性问题. 我怎样才能确保这里的原子性?

其次,当数据库将增长并且艺术家演唱的歌曲将增加时,因此结果文档增长的收集和文档大小可以达到16MB或更大(MAX DOC SIZE).

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

Him*_*ngh 5

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

  • 一首歌可以由多达10位或大约20位艺术家演唱(假设它不像复杂/多样化那样需要100位艺术家).

    在这种情况下,songs收藏艺术家在收藏中的内容非常好,我们可以安全地假设,即使在最糟糕的情况下(存储由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' });
Run Code Online (Sandbox Code Playgroud)

当你解释这个查询时,当你意识到它利用你的多键索引时,你会发现快乐.干得好!

现在采用哪种方法?

我发现第二种方法对于您的用例更为微妙,因为它降低了管理2P提交原子性的一些复杂性,并且仍然提供了良好的读取性能.第一种方法绝对是面向读取的,所以如果你确定你将收到很多很多关于这两个集合的读取,那就去找第一个,否则第二个就应该做.