Reputation: 552
We currently have a CouchDB database with some documents that are created from other documents. This is indicated with a 'forked-from' field in the document.
For example:
{
"_id":"doc_1",
"_rev":"1-a23f9403a1d86648b2a304f5a4c78c31",
"doctype":"entry",
"data":"foo",
"permissions":"private"
}
{
"_id":"doc_2",
"_rev":"1-9c15e43a8c8d4ce1b00af94b328d268d",
"doctype":"entry",
"data":"bar",
"forked_from":"doc_1"
"permissions":"public"
}
{
"_id":"doc_3",
"_rev":"1-b13c761e43121c074c44736826f3ce7e",
"doctype":"entry",
"data":"bat",
"forked_from":"doc_2"
"permissions":"private"
}
We currently have a map/reduce view that will return the number of times a document has been forked, which tells us what the most popular one is.
function (doc) {
if (doc.doctype === 'entry' && doc.forked_from) {
emit(doc.forked_from, 1);
}
}
function(keys, values, rereduce) {
return sum(values);
}
and the result of querying this view with group=true
would be:
{"rows":[
{"key":"doc_1","value":1},
{"key":"doc_2","value":1}
]}
However, what we would like is to only return the documents that have permissions set to 'public', so that the queried result looks like:
{"rows":[
{"key":"doc_2","value":1}
]}
doc_1
should not be returned because it is private.
It doesn't seem that I can filter the results in the map stage, as I only have the doc id, not the entire document to check. I tried adding the document to the key using the linked documents feature and including {'_id': doc.forked_from}
in the emit
of the map, but CouchDB responds with 'include_docs is invalid for reduce views'.
Any suggestions on how I can filter the results of this view?
Upvotes: 2
Views: 1884
Reputation: 36
You say you only have the _id, but you already check for the presence of doc.forked_from, so surely doc.permissions must be available?
So surely your map function would be...
function (doc) {
if (doc.doctype === 'entry' && doc.forked_from && doc.permissions === 'public') {
emit(doc.forked_from, 1);
}
}
Upvotes: 0
Reputation: 2135
I'm fairly new to CouchDB, but you should read:
So I think what you need to do is to make use of complex keys and group_level. The way to do this would be to structure your map function as such:
function (doc) {
if (doc.doctype === 'entry' && doc.forked_from) {
emit([doc.permissions, doc.forked_from], 1);
}
}
The result would be something like this with group=true:
{"rows":[
{"key":["private", "doc_1"],"value":1},
{"key":["public", "doc_2"],"value":1},
{"key":["private", "doc_3"],"value":1},
]}
For you to only obtain the "public" documents, you would have to use a range query together with a group_level query parameter:
http://localhost/db/_design/entry/_view/getNumberForked?startkey=["public", 0]&endkey=["public", {}]&group_level=2
This would give you your result:
{"rows":[
{"key":["public", "doc_2"],"value":1}
]}
I hope this helps you solve your problem.
Upvotes: 2