При разработке своего одного приложения (скоро анонсирую!) я использовал в качестве БД Apache CouchDB, точнее использовал его чуть более продвинутую версию от коммерческой организации – CouchBase. В этом посте я привожу решение нередкой, но нетривиально решаемой задачи (нетривиально для людей, не знакомых до этого с NoSQL).
Задача
Возврат сгруппированных значений по родительскому элементу.
В БД обычно данные хранятся в примерно таком формате:
{ "_id": "256b9dd4492210351c9db34ee500d817", "_rev": "1-94366c1d2b7a075f33ebbd7a96565f4b", "url": "http://surdoserver.ru", "status": 200, "timestamp": 1969072012, "ping": 332 } { "_id": "256b9dd4492210351c9db34ee500f288", "_rev": "1-1770b12a395ca76887c792e5c1d99f8f", "url": "http://surdoserver.ru", "status": 200, "timestamp": 1969073012, "ping": 220 } и т.д.
Нам же необходимо получить статистику по каждому сайту без дублирования информации, то есть что-то типа такого:
{ "url": "http://surdoserver.ru", "data": [ "status": 200, "timestamp": 1969072012, "ping": 332 ], [ "status": 200, "timestamp": 1969073352, "ping": 220 ] }
Решение
Для этого необходимо использовать list-функции, обрабатывающие результаты работы view-функций. View-функция для выборки всех сайтов с их данными выглядит просто:
function(doc) { if (doc.url) emit(doc.url, doc); }
List-функция по-сложнее, но не сильно:
function(head, req) { var row, site, url = "", stats = [], sendData = []; site = getRow(); while (row = getRow()) { if (row.value.url != site.value.url) { //last stat of current site sendData.push({"url" : site.value.url, "data" :stats}); site = row; stats = []; } else { stats.push({ "timestamp": row.value.timestamp, "status": row.value.status, "ping": row.value.ping }); } } sendData.push({"url" : site.value.url, "data" :stats}); send(JSON.stringify(sendData)); }
За основу решения я взял главу из книги «CouchDB: The Devinitive Guide».