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

How to handle Many to Many relationship in mongoDB?

我对 MongoDB 中的多对多关系实现有一个特定问题。

I have collections of Songs and Artists(Millions document). Here the song can be sung by Many Artists and an artist can sing Many songs. So I followed the approach of Document referencing in both collections. like this...

1. 歌曲 Collection:-

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

2. 艺术家 Collection:-

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

But here the problem is while deleting artist I have to delete an artist from an array of the artist in all document of the song which has an artist and vice versa. Which can cause the problem of Atomicity. How can I ensure atomicity here?

Secondly when the database will grow and songs are sung by the artist will increase thus resulting document growth of both collection and document size can reach to 16MB or greater(MAX DOC SIZE).

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

让我们从针对您的案例详细说明我们的 Many-to-Many 关系开始,并尝试了解可以做什么和不能做什么 -

  • 一首歌可以由多达 10 位或 20 位艺术家演唱(假设不像 complex/diverse 那样需要 100 位艺术家演唱)。

    在这种情况下,在 songs collection 中存储艺术家的 ID 非常好,我们可以安全地假设即使在最坏的情况下 (存储 complex/diverse 由 100 位艺术家演唱的歌曲) 它永远不会迫使我们的歌曲 collection 超过 16 MB。

  • 然而,一个艺术家在他的整个职业生涯中可能会演唱多达 1000 首或更多的歌曲。一个 12 字节长的 ObjectId,在这种情况下会将 collection 增长到仅 12000 字节的大小,这远小于 16000000 字节。你还剩下很多space。所以不用担心达到16MB的上限。

方法 - 1

Inter-bucketing works really well for relations expecting high reads.

一些艺术家的歌曲可以在单个查询中获取,反之亦然。如果索引散布在这两个 collection 上,这会更加平滑。

但是,如果我们将艺术家放入歌曲中,将歌曲放入艺术家中,那么我们的更新将不再是原子的,但为此我们仍然可以为艺术家和歌曲 CRUD 实施应用程序级别 Two-phase 提交,即使有点麻烦,也能解决问题。

方法 - 2:

Why not bucket only artist id's inside of songs collection and have multikey index on that field.

演唱歌曲的艺术家列表比艺术家演唱的歌曲列表太短。所以我们只在歌曲 collection.

中存储艺术家

这样我们会-

1. 如果我们在艺术家 collection 中存储歌曲,则避免几乎不可能达到艺术家 collection 的最大大小的可能性。 15=]

2. 避免至少 songs collections 写 2P 提交。所有关系读取只能通过歌曲 collection 来满足(这里我不包括艺术家的 _id 查找)

3. 即使在歌曲 collection 上反向查询艺术家演唱的歌曲时,也能确保在单个查询中快速访问数据。

您已经有了一些艺术家的信息 (_id),您需要为其获取歌曲。您只需像这样起草一个查询 -

 db.songs.find({ artists: 'your-artist-id' });

当您解释这个查询时,当您意识到它利用了您的 multi-key 索引时,您会感到很高兴。干得好!

现在选择哪种方法?

我发现第二种方法对于您的用例来说更微妙一些,因为它降低了为原子性管理 2P 提交的一些复杂性,并且仍然提供了良好的读取性能。第一种方法绝对是面向阅读的,所以如果你确定你会在 collection 上收到大量阅读,请选择第一个,否则第二个应该可以解决问题。

我在 mongodb 中实现了多对多关系,取第三个 collection 类似于我们在 sql 中所做的。

歌曲Collection

{
  _id:ObjectId("dge547567hheheasfw3454df12"),
   title:"xyz",
   length : 123
}

艺术家Collection

{
   _id:ObjectId("dge547567hheheasfw3454d32"),
   name:"abc",
}

歌手Collection

{
   _id:ObjectId("dge547567hheheasdfsdfsdfgdfga42"),
   artist: ObjectId("dge547567hheheasfw3454dfg32"),
   song: ObjectId("dge547567hheheasfw3454df12"),
}
  • 现在当你进行 crud 操作时,如果你想从歌曲中删除艺术家 您可以在 SongArtist Collection.
  • 的单个查询中完成
  • 绝对不会超过文档大小的问题
  • 如果你想删除特定艺术家的特定歌曲 查询一次
  • 它会增加 collection 中的记录数,但 mongodb 可以轻松处理。
  • 您可以在单个查询中找到与一位艺术家相关的所有歌曲,反之亦然。