在 IBM Cloudant 中将相关文档分组在一起
传统上,电子商务系统是使用关系数据库构建的。 这些数据库通常使用多个连接的表来记录销售,客户详细信息,购买的产品和交货跟踪信息。
关系数据库提供高度一致性,这意味着应用程序开发者可以根据数据库的优势来构建其应用程序。 此实践包括集合之间的连接,用于记录对象状态的枚举以及用于保证原子操作的数据库事务。
相对于一致性,IBM® Cloudant® for IBM Cloud® 更偏重于可用性。 它是一个高可用性,容错的分布式数据库,最终保持一致。 分布式数据库意味着客户的购物服务始终可用且可扩展,足以应对许多同时进行购买的用户。 考虑到这一点,您的应用程序可以利用 IBM Cloudant的优势,而不会将其视为关系数据库。
此讨论概述了构建利用 IBM Cloudant的优势的电子商务系统所涉及的一些因素。 IBM Cloudant 使用适用于许多其他域的概念,例如:
- 使用多个文档来表示采购的状态,而不是频繁更新单个文档。
- 按顺序存储相关对象的副本,而不是连接到其他集合。
- 创建视图以按
order_id
整理文档,从而反映出采购的当前状态。
例如,您可以创建包含详细信息 (例如,订购的商品,客户信息,成本和交货信息) 的 purchase
文档。
请参阅描述购买的以下示例文档:
{
"_id": "023f7a21dbe8a4177a2816e4ad1ea27e",
"type": "purchase",
"order_id": "320afa89017426b994162ab004ce3383",
"basket": [
{
"product_id": "A56",
"title": "Adele - 25",
"category": "Audio CD",
"price": 8.33,
"tax": 0.2,
"quantity": 2
},
{
"product_id": "B32",
"title": "The Lady In The Van - Alan Bennett",
"category": "Paperback book",
"price": 3.49,
"tax": 0,
"quantity": 2
}
],
"account_id": "985522332",
"delivery": {
"option": "Next Day",
"price": 2.99,
"address": {
"street": "17 Front Street",
"town": "Middlemarch",
"postcode": "W1A 1AA"
}
},
"pretax" : 20.15,
"tax" : 3.32,
"total": 26.46
}
此文档为购买记录提供了足够的数据,以在 Web 页面或电子邮件上呈现订单摘要,而不访存更多记录。 请注意有关订单的关键详细信息。 具体请参阅以下详细信息:
- basket 包含对存储在其他位置的产品数据库的引用标识 (
product_id
)。 - basket 复制此记录中的一些产品数据,这些数据足以记录在销售点采购的商品的状态。
- 文档不包含用于标记订单状态的字段。 稍后将添加更多文档以记录付款和交付。
- 数据库在将文档插入到数据库中时,会自动生成文档
_id
。 - 每个采购记录都提供有唯一标识 (
order_id
),以便日后引用该订单。
当客户下订单 (通常是在他们进入 Web 站点上的检出阶段时) 时,将创建类似于先前示例的采购订单记录。
生成自己的唯一标识 (UUID)
在关系数据库中,通常使用顺序 "自动递增" 数字。 在分布式数据库中,数据分布在服务器集群中,并且使用更长的 UUID 来确保使用其唯一标识存储文档。
要创建要在应用程序中使用的唯一标识 (例如 order_id
) ,请在 IBM Cloudant API 上调用 GET _uuids
端点 。 数据库将为您生成一个标识。 通过添加 count
参数,可以使用同一个端点来生成多个标识,例如 /_uuids?count=10
。
记录付款
当客户成功支付其商品时,会将更多记录添加到数据库以记录订单。
付款记录的示例
{
"_id": "bf70c30ea5d8c3cd088fef98ad678e9e",
"type": "payment",
"account_id": "985522332",
"order_id": "320afa89017426b994162ab004ce3383",
"value": 6.46,
"method": "credit card",
"payment_reference": "AB9977G244FF2F667"
}
...
{
"_id": "12c0ea6cd3d2c6e3b1d34442aea6a2d9",
"type": "payment",
"account_id": "985522332",
"order_id": "320afa89017426b994162ab004ce3383",
"value": 20.00,
"method": "voucher",
"payment_reference": "Q88775662377224"
}
在上面的示例中,客户是通过提供信用卡和兑换预付券付款的。 这两笔付款加总后等于订单金额。 每笔付款都作为单独的文档写入 IBM Cloudant。
您可以通过创建您所知有关 order_id
的所有信息的视图来查看订单的状态。 该视图将启用包含以下信息的分类帐:
- 采购总计作为正数。
- 针对帐户的付款作为负数。
可以使用 map 函数来标识必需的值。
用于查找采购总计和付款值的示例 map 函数
function (doc) {
if (doc.type === 'purchase') {
emit(doc.order_id, doc.total);
} else {
if (doc.type === 'payment') {
emit(doc.order_id, -doc.value);
}
}
}
使用内置 _sum
减速器 来生成作为支付事件分类帐的输出。
使用内置 _sum
reducer 的示例(使用 ?reduce=false
进行查询)
{
"total_rows":3,"offset":0,"rows":[
{
"id":"320afa89017426b994162ab004ce3383",
"key":"985522332",
"value":26.46
},
{
"id":"320afa89017426b994162ab004ce3383",
"key":"985522332",
"value":-20
},
{
"id":"320afa89017426b994162ab004ce3383",
"key":"985522332",
"value":-6.46
}
]
}
或者,可以生成按 order_id
分组的总计。
按 order_id
分组的总计示例,其中 ?group_level=1
{
"rows":[
{
"key":"320afa89017426b994162ab004ce3383",
"value":0
}
]
}
由于上一个示例中的视图针对订单值返回 0 ,因此结果指示订单已完全支付。 原因是正采购订单总额取消负支付金额。 在 IBM Cloudant中,最好将事件记录为单独的文档,例如,一个用于订单,一个用于支付。 这种做法避免了当多个进程同时修改同一文档时产生冲突的可能性。
添加更多文档
您可以将其他单独的文档添加到数据库,以在供应和分派订单时记录以下状态更改:
- 分派 通知
- 交货收据
- 退款记录
当数据到达时, IBM Cloudant 分别写入每个文档。 因此,不需要修改核心购买文档。
在 IBM Cloudant 中存储采购单的优势
使用 IBM Cloudant 来存储采购订单信息允许订购系统具有高可用性和可伸缩性。 通过这样的排序系统,您可以处理大量数据和高并发访问率。 通过对仅写入一次的单独文档中的数据进行建模,您可以确保文档不会发生冲突,例如,在单独的进程对同一文档进行并发访问期间。
此外,文档可以包含其他集合中存在的数据的副本,以表示(而不是依赖于)使用外键连接数据。 例如, IBM Cloudant 记录购物篮在购买时的状态。 此记录允许通过对 IBM Cloudant 视图的单个调用来访存订单的状态,该视图对 order_id
相关文档进行分组。