在CouchDB中实现外键的惯用方法是什么?

时间:2009-11-04 14:27:50

标签: foreign-keys couchdb

让我举一个简单的例子:你有一个订单和一个购物车。我设想坚持这一点的一种方法是保存订单文档和购物车文档。订单文档可以有一个名为“shopping-cart”的字段,其值是相关Cart文档的UUID。我可以想象的另一种方法是使用包含整个Cart的关联数组的“shopping-cart”字段保存Order文档。换句话说,我没有将Cart明确地保存为独立文档,而是将Cart文档嵌入Order文档中。

如果我们稍后决定购物车应该是持久性的,那么返回的用户会发现他的半成品购物车在会话中等待他?我想我们可以将这两种方法结合起来,在购物车不完整时将其分开,并在最终确定/购买时将其嵌入订单文件中。

虽然我担心CouchDB没有外键约束,但两种方法都可行。在第一种方法中,Cart文档可能会被删除,从而使您的数据集损坏。

您如何决定使用哪种方法?这些方法中的一种对CouchDB来说更具惯用性吗?我错过了哪些方法?

我是CouchDB的新手,因此我很难看到具有或多或少标准化结构的优点/缺点。

2 个答案:

答案 0 :(得分:4)

另一方面,如果他们不是一对一,那么使用复杂的密钥,你可以使用视图整理来进行连接。

function(doc) {
  if (doc.type == 'order') {
    emit([doc.cartid, 1], doc);
  } else if (doc.type == 'cart') {
    emit([doc.id, 0], doc);
  }
}

文件将由cartid与购物车后面的订单进行整理。您的应用程序代码可以轻松加入此流,您可以使用startkey和endkey通过特定的cartid进行查询。

请参阅:View Collation了解整理规则。

您也可以使用缩进将它们连接在一起。

只需将地图功能更改为:

function(doc) {
  if (doc.type == 'order') {
    emit([doc.cartid, 1], {cartid: doc.cartid, orders: [doc]});
  } else if (doc.type == 'cart') {
    emit([doc.id, 0], {cartid: doc.id, orders: [], cart: doc);
  }
}

并添加如下的reduce函数:

function(keys, values) {
  var out = {cartid: null, orders: [], cart: null};
  for (idx in values) {
    var doc = values[idx];
    out['cartid'] = doc.cartid;
    if (doc.cart) { out['cart'] = doc.cart };
    for (idx2 in doc.orders) {
      out.orders.push(doc.orders[idx2]);
    }
  }
  return out;
}

这将返回每个购物车的单个文档,其中包含一个cartid,一系列订单文档和一个购物车文档。

如果上述代码中存在错误,但我没有使用couchdb测试实例来试用它们,请为此道歉。你应该得到一般的想法,而CouchDB wiki有更多的细节。

答案 1 :(得分:0)

如果Order和Cart对象具有一对一的关系(听起来就是这样),那么第二种方法最有意义......只需将关联的对象保存在一个中即可。这为您提供了所需的数据完整性,并使其变得简单; - )