【问题标题】:many to many relationship with nosql (mongodb and mongoose)与 nosql 的多对多关系(mongodb 和 mongoose)
【发布时间】:2014-09-25 21:44:36
【问题描述】:

我正在使用 mongoDb 和 mongoose.js 与多对多建立关系,我知道有很多选择,我的情况是这样的:

我有两个文档,用户和项目,一个用户可以有很多项目,一个项目可以有很多用户,所以在我的例子中我有 4 个选项:

1 - 项目文档中的 id_user 数组。

2 - 用户文档中的 id_project 数组。

3 - 项目文档中的 id_user 数组 && 的数组 id_project 在用户文档中。

4 - 映射用户和项目关系的第三个表(如 关系数据库)。

选项 1 和 2 不可用,因为,假设在选项 1 的场景中,如果我想查找用户的所有项目,我将不得不在用户的每个项目文档数组中查找此用户 ID(在每个项目中遍历这个数组),这绝对不是一个好方法。

选项 3 很好,但我必须进行某种交易以确保两个文档都被写入,这还不错,因为两个文档的读取量都比写入量多得多

选项 4 更简单,因为当我将一个用户添加到项目时,它只是添加一个具有两个 id 的新文档(我认为这是一个很好的解决方案,因为我不需要关心事务,这是一个很好的解决方案?)

那么,最好的解决方案是什么?

【问题讨论】:

    标签: mongodb mongoose nosql


    【解决方案1】:

    相反,解决方案 1 和 2 是您的最佳选择。当更新/创建频率与项目和用户的读取频率相比非常少时,可以考虑解决方案3,因为即使更新/创建需要两次查询,阅读的便利性将弥补这一点。

    要在解决方案 1 和 2 中进行选择,您需要考虑读取频率。您是否需要更频繁地使用用户的项目或项目的使用并据此选择。如果您觉得两者的频率相对相同,则最好使用户对象尽可能少聚集。无论您选择什么选项,请考虑在存储_ids(项目或用户)的阵列上保留一个index

    例如

    userSchema = new Schema(
                {//otherstuff
                   project_ids: [{type: Schema.Types.ObjectId, ref: 'Project'}})
                  ...
                }) 
    userSchema.index({'project_ids':1})
    

    projectSchema = new Schema(
                {//otherstuff
                   user_ids: [{type: Schema.Types.ObjectId, ref: 'User'}})
                  ...
                }) 
    projectSchema.index({'user_ids':1})
    

    _id 数组上保留索引将大大提高您的查询速度,避免您担心会产生大量开销。

    但只有当这个关系是一个重要的关系并且有很多查询正在进行时才保留index。如果这只是您项目的一个附带功能,您也可以将without 设为索引。

    如果用户可以做很多事情并且有很多关系,那么您将在整个应用程序中不断地需要该用户对象,因此如果您的应用程序不是特定于项目的,最好不要将项目 ID 放入用户架构。但是,由于我们只是放置 id,所以无论如何开销都不是很大。不用担心。

    两个数组上的注册索引:是的,你当然可以。但是,当您选择解决方案 3 时,您根本不需要索引,因为您不会进行查询来获取用户的项目列表或项目中的用户列表。解决方案 3 使阅读变得非常容易,但编写起来有点麻烦。但是正如您提到的,您的用例涉及reading>>writing,请使用解决方案 3,但始终存在数据不一致的危险,您需要注意。

    索引只是让事情变得更快。通过the docs 并进行一些谷歌搜索。没有什么花哨。查询索引数组比普通数组更有效。例如。让我们假设您使用解决方案 2。 将项目 ID 存储在 project_ids 字段中。

    您可以轻松获取用户的项目。这是直截了当的。

    但是要获取 project1 的用户。你需要这样的查询。

    User.find({project_ids:project._id},function(err,docs){
         //here docs will be the list of the users of project1
    })
    //The above query might be slow if the user base is large. 
    //But it can be improved vastly by indexing the project_ids field in the User schema.
    

    与解决方案 1 类似。每个项目都有 user_ids 字段。假设我们有一个 user1。 要获取用户的项目,我们执行以下查询

    Project.find({user_ids:user1._id},function(err,docs){
          //here docs will be the projects of user1
          //But it can be improved vastly by indexing the user_ids field in the Project schema.
    

    如果您正在考虑解决方案 1 与解决方案 2,我想解决方案 1 更好。在某些情况下,您可能需要没有他的项目的用户,但需要没有用户的项目的可能性非常低。但这取决于您的具体用例。

    【讨论】:

    • "最好让用户对象尽可能少地聚集" 你的意思是什么?我可以在两种模式(项目和用户)中使用这个索引吗?
    • 而解决方案 1 和 2 并不好,因为两种方式的读取量几乎相同,但写入频率却非常低
    • 解决方案 3,我正在考虑进行交易,以确保两个文档都填充数据,如下所示:docs.mongodb.org/manual/tutorial/perform-two-phase-commits
    • 索引基本上是对文档进行排列,使得对索引字段的查询非常快。 1 表示升序索引,您可以使用 -1 进行降序索引。在这里并不重要,但它确实适用于数字和日期。确切地。浏览交易的陷阱(失败场景,即不一致)并评估您的选择。
    • 是的,解决方案 1 是我打算使用的,问题是,我知道索引像普通数组一样更快更高效,问题是,如果我想看一个项目对于各个用户,我将不得不查看所有项目文档,并且在每个项目文档中,遍历 user_id 数组来检查,问题是这样的,你明白吗?但我认为这个解决方案更适合我的情况。
    【解决方案2】:

    解决方案 1 和 2 看起来还不错!如果你索引 ObjectIds 数组,你可以直接访问你想要的。

    解决方案 3 看起来也不错,但是 4,不是真的,您需要更多查询,除非您在项目和用户的关系之间有很多变化,而不是他们本身。

    我更喜欢在数组上有索引的解决方案 1。我想很多时候你需要依赖用户或直接通过 id 来获取项目对象,所以.find() 会做你想做的一切。我认为用最少的信息保持用户模式还不错,它们看起来像隔离对象,您可能需要它们用于其他目的。

    【讨论】:

    • 好的解决方案一个很好,但如果我想从相应用户那里找到所有项目?我将不得不遍历所有项目文档中的用户数组 id 对象?我认为这不是一个好的解决方案,您能否简要解释一下该索引的工作原理?
    • 看看this。获得这些用户所需的只是 .find({user_ids:YOURID}) 并确保它是如此之快,在 mongo shell 中运行它,如下所示:db.collection.find({user_ids:YOURID}).explain() 看看需要多长时间。
    • 多键索引?我会用这个:link有什么区别?
    • 多键索引是用于数组的索引类型。 Mongoose 将自行检测索引类型。所以不用担心。你所做的一切都很好。
    猜你喜欢
    • 2014-01-21
    • 2014-08-15
    • 2015-10-25
    • 2020-06-12
    • 2016-01-21
    • 2012-12-26
    • 2019-08-11
    • 2015-04-07
    • 2018-11-02
    相关资源
    最近更新 更多