在 MongoDB 中建模用户到项目数据库

发布于 2024-12-03 19:43:30 字数 205 浏览 1 评论 0原文

我有两张桌子。

电影,列出数据库中的所有电影。
用户,就有用户。

通常,我会创建一个连接表来将用户连接到电影(例如,用户喜欢某部电影)。

但是,既然在 MongoDB 中无法做到这一点,我该怎么办?我希望能够找到特定用户喜欢的所有电影,以及喜欢特定电影的所有用户以及给定用户组喜欢的电影。

嵌入文档?

谢谢!

I've got two tables.

Movies, which lists all the movies in the database.
Users, which has the users.

Usually, I'd create a join table to connect a user to a movie (as in, the user likes a certain movie).

However, since you can't do that in MongoDB, what should I do? I want to be able to find all the movies a certain user likes, as well as all the users that like a certain movie, and movies that a given set of users like.

Embedded documents?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

友欢 2024-12-10 19:43:30

对于像这样的电影和用户之间的多对多关系,我可能会为每个用户建立单独的集合,但通过嵌入他们的 _id 将喜欢电影的用户非规范化到 movies 集合中name 字段放入 likes 数组中。

这样,您就可以检索喜欢电影的用户的姓名,而无需单独查找 users 集合,但仍然有不会嵌入电影中的额外用户字段。

权衡是,如果用户更改了姓名,您需要更新这两个集合,但我认为这是值得的成本。

db.movi​​es

{
    _id: <objectid>,
    name:"Star Wars",
    likes: [ 
        { userid: <user-objectid>, name: "John Smith" },
        { userid: <user-objectid>, name: "Alice Brown" }
    ]
}

db.users

{
    _id: <objectid>,
    name: "John Smith",
    username: "jsmith",
    passwordhash: "d131dd02c5e6eec4693d"
}

特定用户喜欢的电影

db.movies.find( { "likes.userid": <user-objectid> }, { "name": 1 } );

喜欢特定电影的用户

db.movies.find( { "_id": <movie-objectid> }, 
    { "likes.userid": 1, "likes.name": 1 } );

给定用户组喜欢的电影

db.movies.find( { "likes.userid": 
    { $in: [ <user1-objectid>, <user2-objectid> ] } },
    { "name": 1 } );

For a many-to-many relationship between movies and users like this, I'd probably have separate collections for each, but denormalise users who like a movie into the movies collection by embedding their _id and name fields into a likes array.

This way, you can retrieve the names of users who like a movie without having to make a separate lookup to the users collection, but still have extra user fields that won't be embedded inside movies.

The trade off is that you'd need to update both collections if a user changed their name, but I think that's a worthwhile cost.

db.movies

{
    _id: <objectid>,
    name:"Star Wars",
    likes: [ 
        { userid: <user-objectid>, name: "John Smith" },
        { userid: <user-objectid>, name: "Alice Brown" }
    ]
}

db.users

{
    _id: <objectid>,
    name: "John Smith",
    username: "jsmith",
    passwordhash: "d131dd02c5e6eec4693d"
}

Movies a certain user likes

db.movies.find( { "likes.userid": <user-objectid> }, { "name": 1 } );

Users that like a certain movie

db.movies.find( { "_id": <movie-objectid> }, 
    { "likes.userid": 1, "likes.name": 1 } );

Movies that a given set of users like

db.movies.find( { "likes.userid": 
    { $in: [ <user1-objectid>, <user2-objectid> ] } },
    { "name": 1 } );
一紙繁鸢 2024-12-10 19:43:30

在 MongoDB 中可以做到这一点,只是不能在数据库级别执行“连接”操作,必须在应用程序级别执行。

如果您有数百万部电影和数百万用户,您必须使用连接集合来完成此操作,因为您无法将一部电影或一个用户的点赞数放入任一文档中。

  1. 查找用户并获取他们的 _id
  2. 查找具有匹配 _id 值的 UserMovie 文档
  3. 根据需要查找电影

您可能在此处执行的非规范化是将电影名称存储在 UserMovie 集合中,以便您可以显示用户喜欢的电影,而无需获取每一部都来自电影收藏。

可能的优化
您可以尝试对此方案的一项优化是在 UserMovie 集合中创建包含多个关系的文档,而不是为每个关系使用单个文档(就像在 SQL 中一样)。

例如,如果最常见的访问模式是查找用户喜欢的电影,您可以按用户对它们进行分组,并将它们放入由该用户 ID 索引的一个或多个文档中。看看 这篇博文以获得更完整的解释。

You can do that in MongoDB, you just can't do the 'join' operation at the database level, you have to do it at the application level.

If you have millions of movies and millions of users you have to do it using a join collection because there is no way you can fit the number of likes for one movie or one user into either document.

  1. Lookup the User and get their _id
  2. Lookup the UserMovie documents with matching _id values
  3. Lookup the Movies as necessary

The denormalization you might do here would be to store the Movie names in the UserMovie collection so you can display the movies a user likes without having to fetch each one from the Movie collection.

A possible optimization
One optimization you can try on this scheme is to create documents in the UserMovie collection which contain multiple relationships instead of using a single document for each relationship (like you would in SQL).

For example, if the most common access pattern is finding what movies a user likes, you could group them by user and put them in one or more documents indexed by that user id. Take a look at the StatementGroups in this blog post for a more complete explanation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文