What is the idiomatic way to implement foreign keys in CouchDB?

Let me give you a simple example: you have an order and a shopping basket. One of the ways that I guess is to save the order document and Cart document. An “Order” document may have a field called a “shopping cart” whose value is the UUID of the corresponding Cart document. Another way I can imagine is to save the order document with the “shopping cart” field containing an associative array of the entire Shopping Cart. In other words, instead of saving the cart explicitly as an independent document, I insert the Cart document into the Order document.

What if we decide later that the Basket should be permanent, so the returning user will find his half of the finished basket that is waiting for him through the sessions? I assume that we could then combine both methods, keeping a separate basket until it is incomplete, and embed it in the order document when it is completed / purchased.

Both methods will work, although I'm worried that CouchDB does not have foreign key restrictions; In the first method, the Cart document can be deleted, leaving you with a damaged data set.

How do you decide which method to use? Is one of these methods more idiomatic for CouchDB? Are there any methods that I skipped?

I'm new to CouchDB, so it's hard for me to see the advantages / disadvantages having a more or less normalized structure.

+6
couchdb foreign-keys
source share
2 answers

If, on the other hand, they are not one to one, but with the help of a complex key, you can use view matching for the connection.

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

documents will be matched by potatoes with orders received after the cart. Application code can easily join this stream, and you can request a specific cartridge using the start key and endpoint.

see Viewing Sort Order for Sort Rules.

You can also use a shortcut to combine them together.

Just change the map function to this:

 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); } } 

and add a reduction function, for example:

 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; } 

This will lead to the return of one document to the basket, which will indicate the potatoes, an array of order documents and a basket document.

Sorry if there are errors in the above code, but I don't have a test couchdb instance that I can try. You should get a general idea, although the CouchDB wiki has more detailed information.

+4
source share

If Order and Cart objects are one-to-one (as it sounds), then the second approach makes the most sense ... just keep related objects contained in one. This gives you the data integrity you are looking for and makes it simple :-)

0
source share

All Articles