MongoDb很多人与大关系

时间:2016-05-31 19:40:18

标签: mongodb nosql

我在Stackoverflow中已经阅读了很多文档和示例,但我不确定我的结论,所以这就是我要求帮助的原因。

想象一下,我们有一个集合电影和一个集合用户和我们想知道,哪些用户看过一部电影,哪些电影见过用户。

在MongoDb中设计它的一种方法是:

用户:

{
"name":"User1",
"films":[filmId1, filmId2, filmId3, filmId4] //ObjectIds from Films
}

薄膜:

{
"name": "The incredible MongoDb Developer",
"watched_by": [userId1, userId2, userId3] //ObjectsIds from User
}

好吧,如果用户/电影的数量很少,这可能有用,但是例如,如果我们预计一部电影将拥有800k用户,那么阵列的大小将接近:800k * 12字节~9.5MB BSON文件的最大值接近16MB。

在这种情况下,还有其他方法,而不是典型的关系世界方式,为关系创建一个中间集合?

此外,我不知道读取和解析大约10MB的JSON与传统的关系方式相比是否会有更好的性能。

谢谢

1 个答案:

答案 0 :(得分:2)

对于电影,如果你包括观众,你最终可能会按照正确的说法点击16MB size limit of BSON documents

根据您的使用情况,将用户看到的电影放入阵列是一种可行的方法。特别是如果你想与属性(比如日期和观看地点)建立关系,那么做更新和统计分析会降低性能(首先需要 $unwind 你的文档,后续 $matches 变得更加昂贵,等等。

如果您的关系具有或可能具有属性,我会使用您所描述的经典关系方式,因为它可以回答您最有可能的用例与嵌入一样好,并允许我的经验具有更高的性能: / p>

给定一个像

这样的结构的集合
 {
   _id: someObjectId,
   date: ISODate("2016-05-05T03:42:00Z"),
   movie: "nameOfMovie",
   user: "username"
 }

您可以随时轻松回答以下示例问题:

  1. 对于给定的用户,他在过去3个月内看过哪些电影,按日期降序排列?

    db.views.aggregate([
      {$match:{user:userName, date:{$gte:threeMonthAgo}}},
      {$sort:{date:-1}},
      {$group:{_id:"$user",viewed:{$push:{movie:"$movie",date:"$date"}}}}
    ])
    

    或者,如果您对迭代器没问题,可以更轻松地使用:

    db.views.find({user:username, date:{$get:threeMonthAgo}}).sort({date:-1})
    
  2. 对于某部电影,有多少用户在今年5月30日看过它?

    db.views.aggregate([
     {$match:{
       movie:movieName,
       date{
         $gte:ISODate("2016-05-30T00:00:00"),
         $lt:ISODate("2016-05-31T00:00:00")}
     }},
     {$group:{
       _id: "$movie",
       views: {$sum:1}
     }}
    ])
    

    我在结果中使用聚合而不是.count()的原因是SERVER-3645

  3. 对于给定的电影,请显示所有看过它的用户。

    db.views.find({movie:movieName},{_id:0,user:1})
    
  4. 有一点需要注意:由于我们分别使用了用户名和电影名称,因此我们不需要JOIN(或类似的东西),这应该会给我们带来良好的性能。此外,添加条目时我们不必进行相当昂贵的更新操作。我们只是插入数据而不是更新。