【问题标题】:I'm confused about designing mongo databases (or collection based databases)我对设计 mongo 数据库(或基于集合的数据库)感到困惑
【发布时间】:2017-07-06 07:45:17
【问题描述】:

在设计SQL数据库时,有一定的明确规则(规范化规则)。

所以,给定这个模型:

  • 有些地方
  • 有事件
  • 地点有名称、纬度、经度
  • 事件有名称、开始日期、结束日期
  • 每个活动都在一个地方举办(所以一个地方有很多活动)

在 SQL 中这样设计很容易,有两个表:

Places(placeId, name, lat, lng)
Events(eventId, placeId, name, startDate, endDate)

这是正确的几乎是毋庸置疑的。没有多少选择...

通过这种设计,我有一些好处:

  • 如果我更新了地名,我就不必关心事件了.. 加入就可以了
  • 我可以忘记地点并处理事件(例如:显示按开始日期排序的事件)
  • 我可以忘记事件并处理地点(显示事件按与某些用户的距离排序等)

现在,我正在尝试在 MongoDb 中设计相同的模型,但我不确定,因为有很多替代方法可以实现:

  • 两个集合:地点不包含事件,事件不包含地点(但保留一个 placeId 字段)

    var placeSchema = new mongoose.Schema({
        name: String,
        lat: Number,
        lng: Number,
    });
    
    var eventSchema = new mongoose.Schema({
        name: String,
        startDate: Date,
        endDate: Date,
        placeId: mongoose.Schema.Types.ObjectId,
    });
    
  • 两个集合:包含事件的地点和不包含地点的事件(但保留一个 placeId 字段)

    var placeSchema = new mongoose.Schema({
        name: String,
        lat: Number,
        lng: Number,
        events: [eventSchema]
    });
    
    var eventSchema = ...
    
  • 两个集合:包含事件的地点和包含地点的事件(不同文档中有大量重复数据)

  • 包含事件的地点集合

    var placeSchema = new mongoose.Schema({
        name: String,
        lat: Number,
        lng: Number,
        events: [eventSchema]
    });
    

在所有上述替代方案中,我可以想象麻烦。如果我需要更新一个名称(作为地名或事件名称),我需要在多个文档中更新它。例如,在“一个地点集合”方法中,一个事件不包含一个地点。所以如果我将一个事件对象单独传递给我的视图,视图将不知道包含该事件的地点的任何信息!

所以,我的问题有两个:

  1. 什么是这个模型的好设计?

  2. 为了这篇文章,我简化了模型。但实际上事件有标签,事件和地点都有图片。我可以在这里描述整个模型,但那将是滥用。 我想知道设计 mongoDB 数据库(基于文档的数据库)的规则。规范化规则清楚地说明了如何应用它们以及它们有什么好处(主要是维护,例如更新时的干净代码等)。 这里有明确的规定吗?。此外,这些(规范化)规则非常直观,通过跳过文献,无论如何都可以以正确的方式做到这一点。

【问题讨论】:

  • 您的数据似乎是关系型的,因为您想以多种方式查询它,为什么要迁移到 NoSQL?
  • @AkerbeltZ 是啊.. 发完这篇文章并阅读了几篇文章后,我想我毕竟会使用 SQL ......我只是想学习 mongodb,块上的新手等。还有每次我google nodejs时,mongodb+mongoose都会出现,就像他们住在一起一样
  • 我一开始也犯了同样的错误,然后回到SQL。我认为 NoSQL 是数据库市场的绝佳补充,但明智地使用它很重要。
  • @AkerbeltZ 我认为我没有对 cme​​ts 给予足够的关注,例如“对非关系数据有好处”、“当你不需要连接时很好”等。我现在看到它们是相当字面的.

标签: node.js mongodb mongoose nosql


【解决方案1】:

嗯,这真的取决于你想从你的架构中得到什么。

第一件事:您为“两个集合:包含事件的地点和不包含地点的事件(但保留 placeId 字段)”编写的代码应该是这样的:

var placeSchema = new mongoose.Schema({
    name: String,
    lat: Number,
    lng: Number,
    events: [mongoose.Schema.Types.ObjectId]
});

var eventSchema = ...

由于 mongodb 没有连接,通常您必须进行非规范化,直到您有充分的理由进行规范化。

在您想做的事情中,如果您的地点可能有很多事件,最好以分页模式或类似的方式获取事件,以保持您的查询很小。在那种情况下,我更喜欢“两个集合:包含事件的地点和不包含地点的事件”。 但是,如果您的地方最多有很少的活动,我会将它们全部保存在一个集合中。 此外,如果您想直接访问事件,最好将它们分成两个集合,如果需要,将名称和_id 放在事件集合中(不用担心重复,大多数时候,速度小查询是你必须关心的)。

对于更新,mongodb 提供了很好的更新工具。因此,例如,如果您很少进行更改(例如更改地名),请不要对其进行规范化。

还有一点,猫鼬提供了population等很好的工具。

【讨论】:

  • 在您的“先做一件事”代码中,您建议使用事件 id 列表代替嵌入式事件列表。当我写这种方法时,我正在考虑第二种选择。
  • 好吧,事实上,当您在另一个模式中使用模式时,猫鼬只会使用您的根模式创建一个集合,其中包含子模式作为对象。它有利于代码的可读性和 DRY,仅此而已。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
  • 2013-07-28
  • 2021-07-11
  • 2018-03-12
  • 1970-01-01
相关资源
最近更新 更多