鉴于我有以下产品:
{
"_id": "2666df80782596200fca49557d757870",
"_rev": "3-99382057f6c484526835f1042753ccf2",
"type": "product",
"name": "Shirt",
"hersteller": "oska",
"price": 11.15
}
{
"_id": "2666df80782596200fca49557d758e8c",
"_rev": "1-01cc88e69e5ff30f0d011fdf61fbedbc",
"type": "product",
"name": "Pullover",
"hersteller": "acme",
"price": 7.58
}
订单
{
"_id": "2666df80782596200fca49557d758228",
"_rev": "2-0b4b3a8605893b60c962b8ae78f0b775",
"type": "order",
"orderDate": "01.01.2012",
"positions": [
"2666df80782596200fca49557d757870",
"2666df80782596200fca49557d758e8c"
]
}
我想查询所有订单的_id,orderDate和所有头寸价格的总和。 我该如何处理?
示例:
[
{ "_id": "2666df80782596200fca49557d758228", "orderDate": "01.01.2012", "total": 18.73 }
]
编辑:
这个例子组成了,我知道订单的总数不应该改变历史订单的产品价格变化。对于需要真正“加入”的事情来说,这是一个不好的例子。想象一下,当产品价格发生变化时,我必须更改总数。因此,我不想简单地对总计字段进行非规范化。
当产品发生变化时,可以“修复”订单中的总计。但是,当我有很多不同的文档类型引用产品时,我需要使用某些功能逐个类型地更改它们。
Sean的回答把这个想法放到我的脑海中,我可以用一个改变监听器来修复非规范化的字段,但是每次有些doc类型与另一个相关时我都需要一个监听器 - 听起来像是很多工作。
答案 0 :(得分:1)
我认为最好的方法是让一个_changes监听器在记录变为历史记录时(即只读)用位置中每个产品的价格值更新订单文档。对于过去的订单,价格可能会发生变化似乎是错误的,而且您无法通过兔子洞价格日期范围打印正确的报告/发票....
要解决您所说的问题,如果您有一些可以使用JSON的客户端代码,Linked Documents下指向的技巧可能有所帮助。给定地图函数,如:
function(doc) {
if(doc.type == 'order') {
for(var position in doc.positions) emit(doc._id,{_id: doc.positions[position]});
}
}
您可以使用?include_docs = true& key =" 2666df80782596200fca49557d758228" 返回包含价格在内的订单项的示例订单。
不幸的是,你不能使用带有reduce的include_docs,所以这可能是我提到的_changes守护进程的一个很好的起点,可以创建一个看起来像你想要的最终答案的订单摘要文档。
[编辑添加解决方案] 好吧,我找到了一种方法,但它并不漂亮。
给定具有此视图映射功能的设计文档:
function(doc) {
if(doc.type == 'order') {
for(var p in doc.positions) emit(doc.orderDate, {_id: doc.positions[p]});
}
}
和此列表功能:
function(head, req) {
var count = 0;
var dates = {};
var totals = {};
while(r = getRow()) {
if(!(r.id in dates)) {
count += 1;
dates[r.id] = r.key;
totals[r.id] = 0;
}
totals[r.id] += r.doc.price;
}
start({'headers': {'Content-Type': 'application/json'}});
send('[\n');
for(var order in dates) {
count -= 1;
send(JSON.stringify({'_id': order, 'orderDate': dates[order], 'total': totals[order]}));
send((count > 0)?',\n':'\n');
}
send(']\n');
}
您想要的结果是
/db/_design/[Design Doc Name]/_list/[List Function Name]/[Map Function Name]?include_docs=true
在这种情况下,键值是orderDate ...