MeteorJS + MongoDB: 当用户可以拥有相同的文档时,我应该如何设置我的集合?

3
我不太确定如何用一行话来表达我的问题,但以下是更详细的描述。
我正在构建一个Meteor应用程序,用户可以“拥有”同一份文档。例如,一个用户拥有一张电影列表,当然多个人可以拥有同一部电影。我已经想过几种数据库/集合的结构方式,但不确定哪种最好。
我还应该注意到,电影信息来自外部API,我目前正在将其存储到自己的数据库中,以便在下一次查找时加速。
选项1(我的当前配置):一个集合(电影),存储所有电影及其信息。另一个集合,在每个文档中基于userId存储电影ids列表。启动时,我获取id列表,在我的数据库中查找电影,并将它们存储在本地集合中(共有3个)。我认为这样做的好处是我只需要存储一次电影。到目前为止,我遇到的问题是很难保持同步并在启动时正确加载(等待本地集合填充)。
选项2:一个电影集合,为每个用户存储电影对象列表。这使得初始查找和更新非常简单,但意味着我将多次存储相同的大型文档。
选项3:一个电影集合,每个电影都有一个包含拥有该电影的用户id的数组。这听起来也不错,但当我使用新信息更新电影时,upsert是否有效并保持userid的安全呢?

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Dan Dascalescu
谢谢提供链接。如果我理解正确的话,最好的方式是像这样:{_id: "123", title: "电影标题"..., user_ids: ["1","2","3"]} - zdixon
1个回答

1
Option 3 看起来很明智。某些选择可能取决于每个集合的规模或链接的数量(许多用户是否拥有相同的电影,用户是否拥有许多电影)。
一些有用的代码片段,可用于选项3:
插入或更新电影详情(如果已存在,不会影响文档上的任何其他字段):
Movies.upsert({name: "Jaws"}, {$set: {year: 1975}});

设置用户拥有电影(不会影响其他文档字段。如果数组中已经存在该值,则$addToSet不会将其添加两次,而使用$push则会创建重复项):

Movies.update({_id: ~~some movie id~~}, {$addToSet: {userIds: ~~some user id~~}});

设置用户不再拥有电影:

Movies.update({_id: ~~some movie id~~}, {$pull: {userIds: ~~some user id~~}});

查找用户拥有的所有电影(Mongo自动搜索字段的数组值):
Movies.find({userIds: ~~some user id~~});

查找用户拥有的所有电影,但在结果中排除用户字段(如果movie.userIds是一个大数组,则保持文档小或保护其他用户-电影所有权的隐私):
Movies.find({userIds: ~~some user id~~}, {userIds: 0});

谢谢提供这些代码片段,它们真的帮助我理解了。这听起来是一个不错的方法。我的问题是,无论哪种方式,我都会有一个可变的、未绑定的数组(要么是电影上的用户ID数组,要么是用户上的电影ID数组)。我不确定哪个会更大;这取决于我拥有的用户数量(目前没有,因为我还没有发布它)。虽然,最后一个代码片段似乎比循环遍历用户上的电影ID数组并找到每个电影更具性能优势。 - zdixon
我想事实是,100万人可以轻松拥有同一部电影,但没有人拥有100万部电影。因此也许反过来做可能更好(仍取决于您正在构建的具体内容)。如果您采用反向方式,则需要像这样的代码...`var user = Users.findOne({_id: ~~某个用户~~});` `Movies.find({_id: {$in: user.movieIds}});`我可以使用完整的片段更新答案。 - MarkWheeler
谢谢Mark,最终我还是保留了原来的方案,但改进了我的Mongo查询,这也是我最初做错的地方。我认为这样做很有意义,因为每个用户都会有多个电影列表(包括自定义列表),而一部电影可以出现在多个列表中。到目前为止,它运行得非常好。感谢你和我讨论这个问题。 - zdixon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接