2021年电子商务应用NoSQL数据库设计
由 Mux 主办的 DEV 全球展示挑战赛:展示你的项目!
您正在为电子商务行业开发产品吗?那么您应该订阅我的新闻简报:https://shophackers.news/
在构建电子商务应用时,处理大量数据(例如产品、订单、类别、用户和支付信息)至关重要。本文将介绍构建 NoSQL 数据库模式的基础知识,使其能够快速且可扩展地应用于电子商务场景。
为什么你应该在 2021 年考虑使用 NoSQL 数据库
像 MongoDB 这样的 NoSQL 数据库在现代应用开发项目中仍然非常流行,并且在过去几年中取得了长足的发展。社区发布了许多优秀的软件包,可以帮助用户以高度可扩展的方式使用 NoSQL 数据库,例如模式生成器和经过验证的软件包,用于将其与 JS 前端或 GraphQL API 结合使用。
此外,MongoDB 尤其出色地提供了非常优秀的云解决方案(MongoDB Atlas:https://www.mongodb.com/cloud/atlas),完美契合现代 Web 技术栈。
NoSQL 数据库是电子商务应用的正确选择吗?
如果你过去几年因为听说 NoSQL 数据库不适合处理大量复杂事务数据的应用而放弃了使用它们的想法,那么你应该再试一次。情况已经发生了很大的变化。事实上,Reaction Commerce 早在三年前就写过一篇不错的文章,而这项技术自那时以来又有了更大的进步:https://blog.reactioncommerce.com/why-nosql-databases-are-perfect-for-ecommerce/。
总而言之:使用 MongoDB(以及任何其他 noSQL 数据库),您可以构建安全、可靠、可扩展的基于云的数据库,而且编码起来非常有趣且容易。
创建电子商务应用程序的架构时应考虑哪些因素
构建电子商务体验时,通常需要考虑以下方面:
- 多达数千种产品
- 包含类似CMS内容(例如图片和描述)的产品
- 某些产品可能有多达数千种不同的款式……
- 由许多不同属性定义的变体
- 可能有数千份订单……
- 订单可能包含多个产品(及其变体)
- 订单可能处于不同的状态,并且一天内可能会多次更改。
- 订单可能会分配给客户
- 客户可能是拥有登录名、密码、地址等信息的用户。
- 通常还会有很多内容管理系统(CMS)内容,例如博客文章、营销落地页等。
- 以及更多
如您所见,您应该确保您的数据库能够处理大量相互连接的数据集。
嵌入数据:快速轻松地处理数据
使用 MongoDB 时,您会在数据库中创建基于 JSON 的条目(称为“文档”),并将它们分组到所谓的“集合”中。
例如,“产品”集合包含多个文档,而每个文档都包含一个产品的数据,例如:
// a document in the "products" collection
{
"_id" : ObjectId("5e451f4cd249baf1d045a778"),
"title" : "Hackathon T-Shirt",
"price" : 3.99,
"currency" : "USD",
"description" : "My Awesome Shirt",
"sku": "DEV1337",
"createdAt" : ISODate("2021-01-02T10:05:00.610Z"),
"stock" : 12,
"sizes": ["xs","s","m","l","xl","xxl"],
"colors": ["red","green","blue"],
"vendor" : "DEVSHIRTS",
"vendorSlug": "devshirts",
"vendorDescription": "DEVSHIRTS is a fashion label that sells T-Shirts for devs."
}
查询嵌入式数据
在这个例子中,我已将此产品的所有数据嵌入到其文档中。通过将数据直接嵌入到对象中,我可以使用单个查询获取包含所有属性的产品,如下例所示:
const product = db.products.findOne({"sku":"DEV1337"}).fetch();
const productTitle = product.title; // "Hackathon T-Shirt"
const vendor = product.vendor; // "DEVSHIRTS"
const amountSizes = product.sizes.length // 6
非常简洁易写,对吧?不过,需要注意的是,查询多个产品时会返回该产品及其所有属性,文件大小可能高达16MB。
修改嵌入数据
假设某个供应商有 1000 多种产品,您决定更改该供应商的描述。现在,所有 1000 多种产品都需要进行相同的操作,即更改需要更改的“vendorDescription”字段。
db.products.updateMany({vendor: "DEVSHIRTS"}, {$set: {vendorDescription: "DEVSHIRT's new description"}});
这类操作虽然易于编写代码,但如果需要在庞大的数据库中每分钟甚至每秒执行多次,则可能需要大量的处理能力。一种解决方案是引用数据,而不是将其嵌入到对象中。
引用数据:处理分布式数据集
您可能熟悉这种处理来自 MySQL 等常规 SQL 数据库的数据的方法。您无需将所有数据添加到同一个文档中,只需像我在这里为供应商所做的那样,向另一个集合中的另一个条目添加一个引用 ID:
//a document in the "products" collection:
{
"_id" : ObjectId("5e451f4cd249baf1d045a778"),
"title" : "Hackathon T-Shirt",
"price" : 3.99,
"currency" : "USD",
"description" : "My Awesome Shirt",
"sku": "DEV1337",
"createdAt" : ISODate("2021-01-02T10:05:00.610Z"),
"stock" : 12,
"sizes": ["xs","s","m","l","xl","xxl"],
"colors": ["red","green","blue"],
"vendor" : "23ae11d117baf1d127c99efd334"
}
//a document in the "vendors" collection:
{
"_id" : ObjectId("23ae11d117baf1d127c99efd334"),
"title" : "DEVSHIRTS",
"slug": "devshirts",
"description": "DEVSHIRTS is a fashion label that sells T-Shirts for devs."
}
查询引用数据
查询引用数据时,需要编写第一个查询来获取引用的 ID,然后再编写第二个查询来获取要查找的对象:
// Want to get the vendor description of a product...
const product = db.products.findOne({"sku":"DEV1337"}).fetch();
const vendorId = product.vendor; // "23ae11d117baf1d127c99efd334"
const vendor = db.vendors.findOne({"_id":vendorId}).fetch();
const vendorDescription = vendor.description
也可以在数据库层面使用 $lookup 函数来实现这一点:https://kb.objectrocket.com/mongo-db/how-to-use-the-lookup-function-in-mongodb-1277
修改引用的数据
使用引用数据而非嵌入式数据的一个显著优势是:您需要更新的文档数量大大减少,可能只需要更新一个文档。例如,现在只需一次高效的操作即可更新供应商的描述:
db.products.update({vendor: "DEVSHIRTS"}, {$set: {vendorDescription: "DEVSHIRT's new description"}});
即使你的数据库中有来自该供应商的数千种产品,MongoDB 也只需要更新一个条目。
何时使用嵌入式数据,何时使用引用式数据
在构建数据库模式时,决定是嵌入数据还是引用数据是最重要的方面之一。
引用数据看似是一种“简洁”的方式,但当你创建尽可能多的引用时,需要编写的代码和查询数量会急剧增加——想想我上面提到的产品示例,其中包含了尺寸、颜色、货币等引用。
此外,你的数据库还会被大量的查询和操作淹没,而这些操作原本只需嵌入数据即可。
另一方面,过多的嵌入数据可能意味着你需要查询和处理远超实际需求的对象,这也会降低应用程序的运行速度。
仅在需要时参考
根据我的经验,最佳实践是尽可能多地嵌入数据,只有在真正需要并且对你的特定应用有意义时才引用其他文档。
例如,如果您只需要为某个产品添加几个具有独特属性的变体,则无需为此创建“变体”集合。另一方面,如果您的变体本身就是拥有众多属性(例如标题、图片、SKU、价格等)的独立产品,甚至在多个产品之间共享,那么最好将它们放在单独的“变体”集合中,以便您可以独立于产品本身查询和修改它们。
提示:数据模型可能派上用场
通常情况下,根据数据模型选择模式也很有帮助。嵌入式数据通常适用于“一对一”和“一对少”关系,而引用式数据则更适合“一对多”关系,尤其是“一对多”关系。
接下来会发生什么?
我希望这篇文章能让您对嵌入式数据和引用式数据有一个基本的了解,并且现在您对构建电子商务数据有了一些概念。
如果您想了解更多,MongoDB 提供了一些非常不错的教程、指南和演示文稿,您可以参考以下链接:
https://docs.mongodb.com/manual/applications/data-models/
https://www.mongodb.com/blog/post/performance-best-practices-mongodb-data-modeling-and-memory-sizing
https://www.mongodb.com/presentations/schema-design-best-practices-series-modelling-relationships