CouchDB: запрашивает отношения «многие ко многим» - PullRequest
1 голос
/ 28 марта 2012

Учитывая, что у меня есть следующие продукты:

{
   "_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 }
]

Edit:
Этот пример составлен, и я знаю, что общая сумма заказа не должна изменять цены продукта для исторических заказов. Это плохой пример для чего-то, где было бы необходимо настоящее «соединение». Просто представьте, что я должен изменить итоги, когда цена продукта изменится. Следовательно, я не хочу просто денормализовать поле итогов. Целесообразно «фиксировать» итоги в заказах при изменении продукта. Однако, когда у меня много разных типов документов, относящихся к продукту, мне нужно менять их тип за типом с помощью некоторой функции. Ответ Шона навел мне на мысль, что я могу исправить денормализованные поля с помощью прослушивателя изменений, но мне понадобится один прослушиватель на каждый раз, когда какой-то тип документа связан с другим - звучит как большая работа.

1 Ответ

1 голос
/ 29 марта 2012

Я считаю, что лучшим способом было бы иметь слушателя _changes, который обновляет документы заказа со стоимостью цены каждого продукта в позициях, когда запись становится исторической (то есть, только для чтения).Просто кажется неправильным, что цена может измениться для прошлого заказа, и вы не можете распечатать правильный отчет / счет-фактуру, не пройдя вниз по диапазонам цен кроличьей норы ....

Чтобы решить проблемукак вы заявили, если у вас есть некоторый код на стороне клиента, который может работать с JSON, может помочь трюк, указанный в Связанные документы .Учитывая функцию карты, такую ​​как:

function(doc) {
 if(doc.type == 'order') {
  for(var position in doc.positions) emit(doc._id,{_id: doc.positions[position]});
 }
}

, вы можете использовать ? Include_docs = true & key = "2666df80782596200fca49557d758228" , чтобы вернуть ваш пример заказа с позициями, включая цену.

К сожалению,, вы не можете использовать 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 ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...