You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@couchdb.apache.org by Ryszard Szopa <ry...@gmail.com> on 2008/06/10 09:24:41 UTC

how to do it in couchDB

Let's say I have a database with objects that may look either like

{type: "user", _id: "foobar", team: "the_foobars"}

or like

{type: "score", user: "foobar", value: 5}.

So, there are some users that belong to teams, and there are their
scores, in which the attribute "user" is a reference to th person that
has achieved the score.

It is very easy to fetch a user and his results using view collation
as proposed in [1] by passing the following view a key argument with
the user id:

function(doc) {if (doc.type == "user") {emit([doc._id,1], doc);} else
if (doc.type == "score") {emit([doc.user,2], doc.value);}}

We can then use a reduce function (which should ignore the first
document, which is a user) to get the mean of the results achieved by
the user.

It is also easy to fetch all the users in a team (just make doc.team
the key if doc.type is "user"). What should I do, however, if I want
to have the mean score of a team?

I was thinking of two approaches.

a) Scores could have a team attribute.

b) Write a complex reduce function which would return what I want.

(a) doesn't seem good because it introduces too much denormalization
to my taste (also, if then a user changes his team, you have to change
all his scores). (b) neither seems good because it isn't much better
than just doing the right calculation on the client side (well, maybe
except caching).

The most natural way of solving this problem would be to first have a
view with a map emitting users and their scores, keyed by user_id, and
a reduce that groups a user and his results in one object, and *then*
run a query on this, mapping teams-names to lists of results and
reduce it to get the mean. Unfortunately, I have no idea if something
like this is possible in CouchDB.

Is there some way of doing something like this? Is the possibility of
doing something like this planned as a future functionality? Or (this
is the answer I would be most happy about ;)) there is some other,
natural way of achieving the same result I just missed?

(My hopes are somehow boosted by the planned grouped reduce functionality).

Cheers,

    -- Richard

[1] http://www.cmlenz.net/archives/2007/10/couchdb-joins
-- 
http://szopa.tasak.gda.pl/

Re: how to do it in couchDB

Posted by Chris Anderson <jc...@grabb.it>.
On Tue, Jun 10, 2008 at 12:24 AM, Ryszard Szopa <ry...@gmail.com> wrote:
> The most natural way of solving this problem would be to first have a
> view with a map emitting users and their scores, keyed by user_id, and
> a reduce that groups a user and his results in one object, and *then*
> run a query on this, mapping teams-names to lists of results and
> reduce it to get the mean. Unfortunately, I have no idea if something
> like this is possible in CouchDB.

I'm planning to add some functionality to CouchRest, which will
automatically take the results of a group=true reduce query, page
through them, adding all the key/value pairs as documents in another
database.

I plan to call the functionality Remap - hopefully I'll have it
written sometime this week.

Writing additional queries as map/reduce views on the derived dataset
would give you a lot of flexibility. For instance, writing maps across
the Remap set would allow you to sort by group reduce value, making it
easy to query on the popularity of certain items in the set - or total
and average scores for a team, in your case.

The only problem is that the second dataset won't automatically be
kept up to date by CouchDB, and the nature of views makes it hard to
refresh the derived dataset in any other way than by regenerating the
whole thing (paging through the reduce set again.)

Chris

-- 
Chris Anderson
http://jchris.mfdz.com