Reputation: 38499
I've got a view on my couch db, which outputs data in this format:
{"rows":[
{"key":["Partner1","Voucher Type 1"],"value":true},
{"key":["Partner1","Voucher Type 2"],"value":true},
{"key":["Partner2","Voucher Type 1"],"value":true},
{"key":["Partner3","Voucher Type 1"],"value":true},
{"key":["Partner4","Voucher Type 1"],"value":true}
]}
What I'm trying to get do is effectively 'group' the Partner | Voucher Type, So in the example above, It would return be something like:
Partner1: ["Voucher Type 1", "Voucher Type 2"]
Partner2: ["Voucher Type 1"]
Partner3: ["Voucher Type 1"]
Partner4: ["Voucher Type 1"]
Currently, my map reduce functions look like this:
Map:
function(
emit([doc.PartnerName, doc.VoucherType], 1);
}
Reduce:
function(keys, values) {
return true;
}
I'm querying with group=true
I suspect I need to do more in the reduce function?
Upvotes: 3
Views: 9754
Reputation: 38749
Your aim is not to reduce the amount of data, only to change the format. So do not use a reduce function, use a list function.
function(head, req) {
var lastKey, row, dedup;
while (row = getRow()) {
if (row.key !== lastKey) {
dedup = {};
send('\n' + row.key + ': ');
}
if (!dedup[row.value]) {
if (row.key === lastKey) {
send(', ');
}
dedup[row.value] = true;
send(row.value);
}
lastKey = row.key;
}
}
This one just gives you a plaintext listing, but you can add whatever formatting you desire, e.g. JSON.
Partner1: Voucher Type 1, Voucher Type 2
Partner2: Voucher Type 1
If you don't need the de-duplication, then it's even simpler.
Upvotes: 2
Reputation: 38499
I got it working by using the following reduce:
function(keys, values, rereduce){
var item = {};
r=[];
values.forEach(function(value){
item[value] = value;
});
for(var i in item){
r.push(item[i]);
}
return r;
}
Comments welcome if this is incorrect, but it's returning me the data in the desired form:
PartnerName: VoucherType[]
Upvotes: 1
Reputation: 619
Consider the following design document:
{
"_id": "_design/ddoc",
"views": {
"partners": {
"map": function(doc) {
emit(doc.PartnerName, doc.VoucherType);
},
"reduce": function(keys, values) {
var voucherTypes = [];
values.forEach(function(v) {
voucherTypes = voucherTypes.concat(v);
});
return voucherTypes;
}
}
}
}
What you could do is to make use of the reduce function with the group=true
parameter, i.e.
<couchdb>/<database>/_design/ddoc/_view/partners?group=true
which would give you something like this:
{"rows":[
{"key":"Partner1","value":["Voucher Type 2","Voucher Type 1"]},
{"key":"Partner2","value":["Voucher Type 1"]},
{"key":"Partner3","value":["Voucher Type 2"]}
]}
However, this is rather discouraged because you are building up data structures in a reduce function. Reduce functions should return simple, usually numeric values. Also, the above reduce function might break in a rereduce case. I have not tested this. As an alternative I can propose to realize the query only with the map function, that is
<couchdb>/<database>/_design/ddoc/_view/partners?reduce=false&key="Partner1"
which would return:
{"total_rows":4,"offset":0,"rows":[
{"id":"97c7ee4d90f57407bb1f4f680d20967b","key":"Partner1","value":"Voucher Type 1"},
{"id":"97c7ee4d90f57407bb1f4f680d20a049","key":"Partner1","value":"Voucher Type 2"}
]}
Upvotes: 1