You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@couchdb.apache.org by Matteo Caprari <ma...@gmail.com> on 2009/12/15 15:40:29 UTC

returning document list and a count of related documents

Hello.

Following a popular example, say I have tow classes of documents in my
database, posts and comments:

{ id:'post-1', type:'post', subject:'first post', body:'...'}
{ id:'post-1-comment-1', type:'comment', post:'post-1' , body:'first comment'}
{ id:'post-1-comment-2', type:'comment', post:'post-2' , body:'second comment'}

{ id:'post-2', type:'post', subject:'second post', body:'...'}
{ id:'post-2-comment-1', type:'comment', post:'post-1' , body:'first comment'}

I'd like to have view with all posts and a count of comments.

{ id:'post-1', type:'post', subject:'first post', body:'...', comments:2}
{ id:'post-2', type:'post', subject:'secong post', body:'...', comments:1}


I was able to obtain what I wanted with a list function, but I was
hoping to do it using only a view.

I've tried with the map/reduce below, but I get the reduce_overflow error
// map.js
function(doc) {
  if (doc.type == "post") {
    map([doc._id, 0], doc);
  } else if (doc.type == "comment") {
    map([doc.post, 1], doc);
  }
}

// reduce.js
function(keys, values, rereduce) {
	log('>>>>>>');
	log('>>>>>>');
	var result = {};

	if (!rereduce) {
		values.forEach(function(doc) {			
			log({doc:doc});
			// this is a question
			if (doc.type == "post" ) {
				if (result[doc._id])
					result[doc._id].subject = doc.subject;
				else
					result[doc._id] = { subject: doc.subject };
			}
			else if (doc.type == "comment") {
				if (!result[doc.post])
                                        result[doc.post] = { comments: 0 };					
				result[doc.post].comments++;					
			}
		});
	}
	else {
		values.forEach(function(value) {					
			for (var post_id in value) {
				if (!result[post_id]) result[post_id] = { subject: '', comments: 0 }
									
				if (value[post_id].subject) {
					result[post_id] = value[post_id].subject;
				}
				if (value[post_id].comments) {
					result[post_id].comments += value[post_id].comments
				}
			}
		});
	}
	log("<<<<<<");
	log("<<<<<<");
	
	return result;
}	

thanks

-- 
:Matteo Caprari
matteo.caprari@gmail.com

Re: returning document list and a count of related documents

Posted by Matteo Caprari <ma...@gmail.com>.
Hi Pawel.

Thanks for your answer.

I was trying to get post data and comment count to generar a posts
list. I kind of gave up and made it with a _list function...

On Tue, Dec 15, 2009 at 11:36 PM, Paweł Stawicki
<pa...@gmail.com> wrote:
> Hmm... Maybe try to have document as a key?
>
> // map.js
> function(doc) {
>  if (doc.type == "post") {
>    map(doc, 0);
>  } else if (doc.type == "comment") {
>    map({'_id':doc.post}, 1);
>  }
> }
>
> // reduce.js
> function(keys, values, rereduce) {
>        return sum(values);
> }
>
>
> Then call view with "group=true" parameter. You should get document as
> key, and number of comments as value.
>
> Another solution, if you need post id as a key and post document as value:
> // map.js
> function(doc) {
>  if (doc.type == "post") {
>    map(doc._id, [doc, 0]);
>  } else if (doc.type == "comment") {
>    map(doc.post, [{'_id':doc.post}, 1]);
>  }
> }
>
> // reduce.js
> function(keys, values, rereduce) {
>  if (!rereduce) {
>    var commentsCount = 0;
>    values.forEach(function(array) {
>      commentsCount += array[1];
>    }
>    return [values[0][0], commentsCount;
>  } else {
>    var commentsCount = 0;
>    values.forEach(function(array) {
>      commentsCount += array[1];
>    }
>    return [values[0], commentsCount;
>  }
> }
>
> WARNING: will work only with "group=true" parameter.
>
> I am not sure it will work, but it definitely won't work with
> group_level = 0 (which is default), so use group=true. It should give
> you post id as a key, and post document and comments count as value.
>
>
> Regards
> --
> Paweł Stawicki
> http://pawelstawicki.blogspot.com
> http://szczecin.jug.pl
> http://www.java4people.com
>



-- 
:Matteo Caprari
matteo.caprari@gmail.com

Re: returning document list and a count of related documents

Posted by Paweł Stawicki <pa...@gmail.com>.
Hmm... Maybe try to have document as a key?

// map.js
function(doc) {
 if (doc.type == "post") {
   map(doc, 0);
 } else if (doc.type == "comment") {
   map({'_id':doc.post}, 1);
 }
}

// reduce.js
function(keys, values, rereduce) {
       return sum(values);
}


Then call view with "group=true" parameter. You should get document as
key, and number of comments as value.

Another solution, if you need post id as a key and post document as value:
// map.js
function(doc) {
 if (doc.type == "post") {
   map(doc._id, [doc, 0]);
 } else if (doc.type == "comment") {
   map(doc.post, [{'_id':doc.post}, 1]);
 }
}

// reduce.js
function(keys, values, rereduce) {
  if (!rereduce) {
    var commentsCount = 0;
    values.forEach(function(array) {
      commentsCount += array[1];
    }
    return [values[0][0], commentsCount;
  } else {
    var commentsCount = 0;
    values.forEach(function(array) {
      commentsCount += array[1];
    }
    return [values[0], commentsCount;
  }
}

WARNING: will work only with "group=true" parameter.

I am not sure it will work, but it definitely won't work with
group_level = 0 (which is default), so use group=true. It should give
you post id as a key, and post document and comments count as value.


Regards
-- 
Paweł Stawicki
http://pawelstawicki.blogspot.com
http://szczecin.jug.pl
http://www.java4people.com