mongodb - noSQL的实际用法

标签 mongodb database-design database nosql

我正在启动一个新的web项目,必须决定使用什么数据库。我知道,这个问题很长,但请容忍我。
我非常熟悉关系数据库,并使用了hibernate等框架将数据库中的数据转换成对象。但我没有使用nosql dbs的经验。我知道文档、键值等类型的概念。
当我做研究时,每次都会弹出一个问题,我不知道在像mongodb这样的nosql dbs或任何其他文档类型的nosql db中,一致性是最重要的。
例如:假设我们正在创建一个小型购物管理系统,客户可以在其中买卖商品。
我们有:
客户
命令
产品
一个客户可以有多个订单,一个订单可以有多个产品。
在传统的rdbms中,我当然有3个表。
在我们的应用程序的第一个版本中,客户的前端应该显示他/她的个人数据、订单和他/她每次订单购买的所有产品。还有哪些产品可以出售。所以我想在NoSQL中,我会将客户类建模如下:

{
    "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,而不仅仅是第一个ui:
客户仪表板,客户可以在其中查看其所有订单。
客户可以在其商店中添加或删除产品的产品仪表板。
已售出的仪表板,客户可以在其中查看所有已售出的准备发货的产品。
一个非常重要的事情要考虑(我甚至会问这个问题的原因):我想灵活地与产品类一样,因为产品可以有不同的特性。例如:电视有屏幕大小和分辨率,而汽车有马力和其他特性。如果用户添加了一个新产品,他/她应该能够根据他/她对产品的了解动态地添加这些属性。
下面介绍两个虚构用户jane和john的一些实际用例:
比方说,简向约翰买东西。这是否意味着我必须创造两次产品?一次是简的命令,另一次是留在约翰的“产品”财产?
稍后,Jane希望查看任何用户提供的所有产品。是否必须加载每个用户才能查询“products”属性以生成所有产品的列表?
在应用程序的版本2中,我想让john能够查看所有的外发订单(不是他下的订单,而是从其他从他那里买东西的用户那里下的订单),而不是查看所有已售出的产品。在nosql中如何实现这一点?我现在需要创建一个“输出”的订单数组并复制它们吗?(简发出的命令是约翰发出的命令)
有些人可能会说nosql不适合这个用例,但这不是很常见吗?尤其是当我们不知道未来会带来什么?如果它不适合这个用例,那么它适合哪个用例?只有婴儿申请(我想没有)?NoSQL不是为更复杂、更灵活的数据而设计的吗?
非常感谢您的建议和意见!
编辑1:
因为这个问题因为这个不精确的问题而被搁置:
我举了一个简单明了的例子。所以我的问题不是关于nosql的使用,而是如何处理这个特定的例子。有经验的nosql用户如何处理这个用例?如何对这些数据建模?建议在这个用例中完全不要使用nosql也是一个有效的答案。
我只想知道如何使用nosql数据库,但仍然能够管理实体和避免冗余。
例如:mongodb的dbrefs/manual refs是实现这一点的好方法吗?多个查询导致的性能问题?还有什么好考虑的?我想这些问题可能会得到很好的回答。

最佳答案

你的问题可能没有一个正确的答案。但我要开始了。
虽然在nosql中技术上可以将一些业务实体与所有与之有传递链接的实体(如客户、订单、产品)存储在一起,但这样做并不总是明智的。分离实体的传统原因,即冗余,因此更新和删除异常,并不仅仅因为使用了不同的平台而消失。
因此,如果您将产品描述与每个购买或销售此产品的客户一起存储,您将得到更新异常。如果必须将屏幕大小从37更改为35,则必须查找包含此产品的所有客户记录,这可能会非常麻烦。
此外,构建这样一个深嵌套结构有利于评估这些结构的一个方向,而不是所有其他方向。如果你把所有的订单和产品都放进客户文档中,这对于全面了解客户是非常好的:无论她一生中买了什么。但如果你想按订单查询你的数据库(哪些订单今晚需要完成?)或产品(谁订购了产品1234?)您将不得不加载大量对此查询不感兴趣的数据。
类似的问题是由于与客户一起存储所有订单。旧订单有时仍会引起兴趣,因此可能不会被删除。但是你想在每次给客户下订单时都下很多订单吗?
这并不意味着不利用文档存储所提供的复杂结构。根据经验,我建议:只要嵌套的信息属于同一个业务实体,就将其放入一个文档中。例如,如果产品描述具有某种层次结构,如由文本、图片和视频组成的嵌套部分,则它们都可以放入一个文档中。但是,具有完全不同生命周期的实体,如客户、订单和供应商,应该保持独立。另一个指标是参考文献:一个产品经常作为一个整体被参考,例如当它是由客户订购或从供应商订购时。但产品描述的不同部分可能永远无法从外部引用。
这条经验法则并不完全准确,也不应该是。一个人的商业实体是另一个人的愚蠢属性。想象一下汽车的颜色:对于车主来说,这只是描述汽车的一条信息。对于制造商来说,它是一个商业实体,拥有可用性、价格、一个或多个供应商、处理方式等。
您的问题还涉及动态添加属性的方面。这经常被称赞为NoSQL的优点之一,但它不是免费的午餐。我们假设,正如您所提到的,用户可以添加属性。这在技术上是可能的,但是系统将如何处理这些属性?这些属性既没有特定的视图,也没有特定的业务规则。因此,系统所能做的最好的事情就是提供一些通用的机制来显示那些在运行时定义但从未在程序代码中反映的属性。
这并不意味着这个功能是无用的。想象一下你的产品描述可能很复杂,如上所述。您可以构建一个通用机制来显示(和编辑)由节、文本、图像等组成的描述,然后用户可以输入无限宽度和深度的描述。但与此相反,假设您的用户将向订单添加一个小的delivery date属性。除非系统明确知道如何解释这个日期,否则它只是一个没有任何影响的愚蠢信息。
现在想象一下,不是用户,而是开发人员添加了新的属性。她有机会同时增强代码,例如围绕交付日期构建一些功能。但这意味着,尽管数据库本身并不需要它,但需要推出新版本的软件来利用新的信息。
缺少数据库方案甚至使程序员的任务更加复杂。当一个关系表有一个特定的列时,您可以确保它的每个记录都有这个列。如果要确保它有一个有意义的值,请将其设置为not null,并且可以确保每个记录都包含一个正确数据类型的值。无模式数据库无法保证这一点。因此,在读取记录时,需要使用防御性编程来确定哪些部分存在,以及它们是否具有预期的内容。通过管理工具维护数据库也是如此。在sql中添加属性并用默认值初始化它是一个2行程序,或者在pgadmin中单击几下鼠标。对于无模式数据库,您将自己编写一个简短的程序来实现这一点。
这并不意味着我不喜欢nosql数据库。但我认为“无模式”的特点有时被高估了,我不会把它作为使用这样一个数据库的主要或唯一理由。

关于mongodb - noSQL的实际用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36495198/

相关文章:

mysql - 获取前 N 行,包括绑定(bind)值 MYSQL

c# - 无法从 MongoDb C# 中的 BsonType ObjectId 反序列化字符串

mongodb - mongorestore 从独立到复制集

cakephp - 是否可以根据主模型的数据进行关联?

mysql - 多个供应商的产品定价历史数据库设计

php - mysqli:像 $new_link=false 一样调用构造函数两次时返回相同的连接;

node.js - docker容器无法连接到本地主机mongodb

python - 如何按 1000 分块读取集合?

java - Neo4j - Java 堆空间。错误的查询或设置?

ruby-on-rails - 如何使用 PSequel GUI 在 Mac 上连接到本地主机 PostgreSQL?