【问题标题】:MongoDB schema design for multiple auth user accounts多个身份验证用户帐户的 MongoDB 架构设计
【发布时间】:2012-06-21 13:12:58
【问题描述】:

我即将构建我的 node.js / express / mongoose / passport 应用程序,我正在考虑正确的 schema 设计用户和帐户。

会有用户从 twitter 和 facebook 以及本地帐户登录。在稍后阶段,我希望用户将 twitter 和 facebook 与我的应用程序(甚至更多外部帐户)连接起来。

对于这种情况,我想不出一个好的解决方案。以下是我正在考虑的选项:

1.拥有档案模型和账户模型。 Profile 文档代表唯一的用户,而帐户提供用户名和密码(内部帐户)或来自 auth-provider(外部帐户)的身份验证数据。个人资料必须至少有一个嵌套帐户文档。

var ExtAccountSchema = new Schema({
    type: String, // eg. twitter, facebook, native
    uid: String
});

var IntAccountSchema = new Schema({
    username: String,
    password: String
});

var ProfileSchema = new Schema({
    firstname: String,
    lastname: String,
    email: String,
    accounts: [Account] // Pushing all the accounts in there
});

我不喜欢的是由于不同的帐户数据导致的帐户文档不一致,而且当我的用户登录时我很难找到正确的帐户(在嵌套文档中搜索 uid 和帐户类型 -.- )

2.将所有数据保存在单个模型

var ProfileSchema = new Schema({
    firstname: String,
    lastname: String,
    email: String,        
    twitter-uid: String,
    facebook-uid: String
    password: String
});

这很丑 -.- 找到正确的帐户数据可能更容易/更快,但维护起来并不好。

有没有更好的解决方案? 有最佳做法吗?

【问题讨论】:

  • 与关系数据库不同,MongoDB 的最佳架构设计很大程度上取决于您将如何访问数据。您会将帐户数据用于什么目的,您将如何访问这些数据?
  • 我将使用帐户数据进行护照身份验证。个人资料数据将在几乎每个页面上以多种用途访问。我将通过 mongoose ODM 访问它
  • 所以只有在用户登录时才能访问帐户数据,并且一旦发生这种情况,您将使用会话机制来跟踪登录? (而不是在每次访问页面时都需要帐户数据。)
  • 我需要每个页面上的用户数据。但我不确定如何构建它。在我的示例中,我将数据分为帐户和个人资料。所以我可以随时访问个人资料和帐户,只为登录。

标签: mongodb express mongoose passport.js


【解决方案1】:

1) 您可以采用三种策略在 MongoDB 中构建数据:

  • a) 嵌入文档数组
  • b) 嵌入引用数组
  • c) 展开到父文档中

策略 (a) 是您描述的第一个策略,其中 Profile 文档包含一组 Account 子文档。

策略 (b) 与策略 (a) 类似,但您将使用对其他文档(通常在 Account 集合中)的引用数组,而不是嵌入实际文档。

策略 (c) 是您描述为“将所有数据放在一个模型中”的策略。

2) 通常认为最佳实践是使用一组嵌入文档,尤其是在其中的信息可能不同的情况下。如果它能让您的生活更轻松,您可以使用一个密钥来区分帐户的类型,如下所示:

  { 
    firstname: 'Fred',
    lastname: 'Rogers',
    email: 'fred.rogers@example.com',

    accounts: [
             { kind: 'facebook',
               uid: 'fred.rogers'
             },
             { kind: 'internal',
               username: 'frogers',
               password: '5d41402abc4b2a76b9719d911017c592'
             },
             { kind: 'twitter',
               uid: 'fredr'
             }
          ]
    }

3) MongoDB 允许您搜索嵌入的文档。因此,您将编写以下查询(JavaScript 语法):

 db.profile.find( 
        { email: 'fred.rogers@example.com', 'accounts.kind': 'facebook' }
        );

有了适当的索引,这个查询会很快。

【讨论】:

  • 写得好答案:-) 谢谢。我正在考虑,但不知道该怎么做。如果可以的话,我会多给一分。再次感谢。
  • 我是否正确地假设我应该使用复合稀疏索引? ProfileSchema.index({accounts.kind, accounts.uid},{unique: true, sparse: true});?
  • 您应该使用复合稀疏索引。复合稀疏索引几乎总是做不到你想要的。请为此打开一个新线程。
  • 如何在 Mongoose 上做到这一点?
【解决方案2】:

我希望它可以帮助像你一样有类似需求的人。

MongoDB 中的架构设计和数据建模

  • SQL 具有固定/严格模式,而 NoSQL 具有动态/灵活模式,即不强制执行文档结构

  • MongoDB有两种数据模型:

    • 嵌入式数据建模:
      • 具有单一文档结构,被称为非规范化模型
      • 支持文档级原子操作。
      • 易于执行 CRUD
      • 在 70% 的情况下使用,并且在读取操作方面表现出色
      • 大小可以轻松达到 16 MB 的阈值,并且容易出现高冗余
      • 建议在一对一和一对多关系中使用
    • 引用或链接数据建模
      • 模仿 SQL 数据库的规范化表以减少数据重复和冗余。
      • reference 或 _id 用于引用另一个文档,类似于在 SQL 中使用主键和外键连接表。
      • 用于 30% 的案例
      • 建议在多对多关系中使用

数据建模的观点

  • 概念数据建模:关于功能和服务的大图,其中还包括
    • ER 数据建模:数据库设计的图形化方法。
    • 架构设计
  • 逻辑数据建模:概念数据建模将使用编程语言、表格等转换为逻辑数据建模(程序)。(服务器代码)
  • 物理数据建模:将逻辑 DM 付诸实践,实际数据由用户插入。(数据库)

数据模型的类型

  • 平面、星形、分层、关系、对象关系

文档之间的模型关系

  • 一般而言,您应该构建架构,以便您的应用程序在一次读取操作中接收所有必需的信息。

使用嵌入式文档建模一对一关系

  - In referenced or normalized data model, If one document is frequetly refering some data in another document, It would create better data model to embed both documents into one.
  - If a single document seems to be large, it is better split your data into referential model, the most frequently-accessed portion of the data should go in the collection that the application loads first
  ```json
  // one person and one address
  {
     _id: "joe",
     name: "Joe Bookreader",
     address: {
              street: "123 Fake Street",
              city: "Faketon",
              state: "MA",
              zip: "12345"
              }
  }
  ```

使用嵌入式文档建模一对多关系

  • 在为其设计模型方面也基于与一对一相同的概念。
// one person and his multiple address
{
   "_id": "joe",
   "name": "Joe Bookreader",
   "addresses": [
               {
                  "street": "123 Fake Street",
                  "city": "Faketon",
                  "state": "MA",
                  "zip": "12345"
               },
               {
                  "street": "1 Some Other Street",
                  "city": "Boston",
                  "state": "MA",
                  "zip": "12345"
               }
            ]
}

使用参考文档建模一对多关系

  • 在某些情况下,最好使用参考模型以获得更好的性能,如下所示。
  • 为避免出版商数据重复,请使用参考资料并将出版商信息保存在与图书收藏不同的收藏中。
   {
   _id: 'some string'
   name: "O'Reilly Media",
   founded: 1980,
   location: "CA",

   books: [123456789, 234567890, ...]

   }

   {
      _id: 123456789,
      title: "MongoDB: The Definitive Guide",
      author: [ "Kristina Chodorow", "Mike Dirolf" ],
      published_date: ISODate("2010-09-24"),
      pages: 216,
      language: "English"
   }

   {
      _id: 234567890,
      title: "50 Tips and Tricks for MongoDB Developer",
      author: "Kristina Chodorow",
      published_date: ISODate("2011-05-06"),
      pages: 68,
      language: "English"
   }
  • 如果将来书籍数组有可能变得庞大,最好将出版商引用存储在书籍文档中。
  • 观察架构中的智能变化,_id 信息(即出版商 ID)如何在 BOOK COLLECTION 中称为 publisher_id
   {
   _id: "oreilly",
   name: "O'Reilly Media",
   founded: 1980,
   location: "CA"
   }

   {
      _id: 123456789,
      title: "MongoDB: The Definitive Guide",
      author: [ "Kristina Chodorow", "Mike Dirolf" ],
      published_date: ISODate("2010-09-24"),
      pages: 216,
      language: "English",

      publisher_id: "oreilly"

   }

   {
      _id: 234567890,
      title: "50 Tips and Tricks for MongoDB Developer",
      author: "Kristina Chodorow",
      published_date: ISODate("2011-05-06"),
      pages: 68,
      language: "English",

      publisher_id: "oreilly"

   }

【讨论】:

    猜你喜欢
    • 2012-08-24
    • 2012-06-13
    • 1970-01-01
    • 2021-12-04
    • 2016-10-11
    • 2018-09-10
    • 1970-01-01
    • 2015-04-21
    • 2018-09-01
    相关资源
    最近更新 更多