我正在开始一个新的Web项目,必须决定使用哪个数据库。我知道,问题很长,但请耐心等待。
我对关系数据库非常熟悉,并且使用了像hibernate这样的框架来将数据从数据库中提取到对象中。但我没有使用noSQL DB的经验。我知道文档,键值等类型的概念 在我做研究的时候,每次都会弹出一个问题而且我不知道有人会在MongoDB或任何其他文档类型的noSQL DB这样的noSQL DB中处理这个问题,其中一致性是最重要的。
例如:我们假设我们正在创建一个小型购物管理系统,客户可以在这里购买和销售东西。 我们有:
单个CUSTOMER可以有多个ORDER,ORDER可以有多个PRODUCT。
在传统的RDBMS中,我当然会有3个表 在我们的应用程序的第一个版本中,客户的前端应显示他/她的个人数据,订单以及他或她为每个订单购买的所有产品。还有哪些产品可供出售。所以我想在noSQL中我会像这样建模CUSTOMER类:
{
"id": 993784,
"firstname": "John",
"lastname": "Doe",
"orders": [
{
"id": 3234,
"quantity": 4,
"products": [
{
"id:" 378234,
"type": "TV",
"resolution": "1920x1080",
"screenSize":37,
"price": 999
}
]
}
],
"products": [
{
"id:" 7932,
"type": "car",
"sold": false,
"horsepower": 90
}
]
}
但后来我想扩展我的应用程序以拥有3个不同的UI,而不仅仅是第一个:
需要考虑的一件非常重要的事情(我甚至懒得问这个问题的原因):我希望对像PRODUCT这样的类很灵活,因为产品可以有不同的属性。例如:电视具有屏幕尺寸和分辨率,而汽车具有马力和其他属性。如果用户添加了新产品,他或她应该能够根据他/她对它的了解动态添加这些属性。
现在来看两个虚构用户Jane和John的一些实际用例:
让我们说,简从约翰那里买来。这是否意味着我必须创建两次PRODUCT?有一段时间作为简的订单的孩子和另一次留在"产品"约翰的财产?
后来Jane希望查看任何用户可用的所有产品。我是否必须加载每个用户才能查询"产品"属性生成所有产品的列表?
在应用程序的第2版中,我希望John能够查看所有传出的订单(不是他订购的订单,而是从他那里购买东西的其他用户的订单),而不是查看所有销售的产品。如何在noSQL中完成?我现在需要创建一个"传出"一系列订单并复制它们? (Jane的传出订单是约翰的传入订单)
有些人可能会说noSQL不适合这个用例,但是不是很常见吗?特别是当我们不知道未来会带来什么?如果它不适合这个用例,它会适用于哪种用例?只有宝宝申请(我猜不是)?是不是针对更复杂,更灵活的数据设计了noSQL?
非常感谢您的建议和意见!
由于这个令人不确定的问题,这个问题被搁置了: 我做了一个非常简单明了的例子。所以我的问题不是关于noSQL的使用,而是如何处理这个具体的例子。经验丰富的noSQL用户如何处理这个用例?如何建模这些数据?对于这个用例,完全不使用noSQL的建议对我来说也是一个有效的答案。
我只是想知道如何使用noSQL数据库,但仍然能够管理实体并避免冗余。 例如:MongoDB的DBRefs / Manual是否是实现这一目标的好方法?由于多个查询,性能问题?还有什么可以考虑的?我想这些问题可能会得到很好的回答。
答案 0 :(得分:2)
你的问题可能没有正确答案。但我会先行。
虽然在NoSQL中技术上可以将一些商业实体与所有与其传递链接的实体(如客户,订单,产品)一起存储,但它始终是聪明的。分离实体的传统原因,即冗余,因此更新和删除异常,并不会因为使用不同的平台而消失。
因此,如果您将产品说明存储在购买或销售此产品的每个客户中,您将获得更新异常。如果您必须将屏幕尺寸从37更改为35,则必须查找包含此产品的所有客户记录,这可能非常麻烦。
此外,构建如此深的嵌套结构有利于在所有其他方向上评估这些结构的一个方向。如果您将所有订单和产品放入客户文档中,这对于获得客户的全面视图非常好:无论她在其一生中购买了什么。但是,如果您想按订单查询数据库(需要在今晚完成哪些订单?)或产品(订购产品1234?),您将需要加载大量此查询不感兴趣的数据。 / p>
类似的问题是由于与客户存储所有订单。旧订单有时仍然会引起关注,因此可能不会删除它们。但是,您是否希望每次加载客户时加载大量订单?
这并不意味着不使用文档存储所能实现的复杂结构。作为经验法则,我建议:只要嵌套信息属于同一个业务实体,就将其放入一个文档中。例如,如果产品描述具有某种分层结构,例如由文本,图片和视频组成的嵌套部分,则它们可能都进入一个文档。但是,与客户,订单和供应商等生命周期完全不同的实体应该分开。另一个指标是参考:产品通常作为一个整体被引用,例如当它由客户订购或从供应商订购时。但产品描述的不同部分可能永远不会从外部引用。
这个经验法则并不完全准确,而且不应该这样。一个人的商业实体是另一个人的愚蠢属性。想象一下汽车的颜色:对于车主而言,它只是描述汽车的一条信息。对于制造商而言,它是一个商业实体,具有可用性,价格,一个或多个供应商,处理它的方式等。
您的问题也涉及动态添加属性的方面。这通常被称为NoSQL的好东西之一,但它没有免费的午餐。如上所述,让我们假设用户可能会添加属性。这在技术上是可行的,但系统如何处理这些属性?对于这些属性,不会是特定的视图,也不是特定的业务规则。因此,系统可以做的最好的事情是提供一些通用的机制来显示那些在运行时定义但从未反映在程序代码中的属性。
这并不意味着该功能毫无用处。想象一下,如上所述,您的产品描述可能很复杂。您可以构建一个通用机制来显示(和编辑)由部分,文本,图像等组成的描述,然后用户可以输入无限宽度和深度的描述。但相比之下,想象一下您的用户会在订单中添加一个小delivery date
属性。除非系统具体知道如何解释这个日期,否则它只是一条愚蠢的信息而没有任何影响。
现在想象不是用户,但开发人员会添加新属性。她有机会同时增强代码,例如在交货日期附近建立一些功能。但这意味着,尽管数据库并不需要它自己,但需要推出新版软件以利用新信息。
缺少数据库方案甚至使程序员的任务更加复杂。当关系表具有某个列时,您可以确定其每个记录都有此列。如果要确保它具有有意义的值,请将其设为not null
,并且您可以确定每条记录都包含正确数据类型的值。无模式数据库无法保证这一点。因此,在阅读记录时,需要采取防御性编程来确定哪些部分存在,以及它们是否具有预期内容。这同样适用于通过管理工具进行数据库维护。添加属性并使用默认值初始化它是SQL中的2行,或者是pgadmin中的几次鼠标单击。对于无模式数据库,您将自己编写一个简短的程序来实现此目的。
这并不意味着我不喜欢NoSQL数据库。但我认为"无模式"特征有时被高估了,我不会把它作为使用这样一个数据库的主要或唯一理由。