dready92 / PHP-on-Couch

Data Access Library to access a CouchDB server with PHP.
http://dready.byethost31.com/index.php/display/view/192
GNU Lesser General Public License v3.0
246 stars 102 forks source link

Howto get reduce working like SELECT DISTINCT field FROM table #20

Closed SMut closed 13 years ago

SMut commented 13 years ago

Hi, everything runs fine so far but now I run into a problem which is far beyond my knowledge about couchDB and the reduce funtions. Let me explain: The thing I want to get out of the database is a key/value pair emitting all the clubs playing in one league. My wish is a return from couch looking like this: { ["verband","landes","regional","kreis","league"]:["club1","club2",...."clubX"] }

What I am using as a view is this: function(doc) { if (doc.kreis ) {emit ( [doc.verband,doc.regional,doc.landes,doc.kreis,doc.staffel], doc.heim); } else { if (doc.landes ) {emit ( [doc.verband,doc.regional,doc.landes,doc.staffel], null); } else { if (doc.regional) {emit( [doc.verband,doc.regional,doc.staffel], null); } else { if (doc.verband) {emit ( [doc.verband,doc.regional,doc.staffel], null); } } } } }

Which gives me the key as an array as expected, but To achieve a 'DISTINCT' like function I use this code in the reduce section: function(keys, values) { return true; } This is just a start, this code reduces the key section in a sql-distinct way, but I have 'true' as a value, but I want distinct (single) club names in an array. To explain the way documents look like: every document displays a handball game, and the handball-clubs appear either as a home- or a guest-team. A loop is needed to get all clubs appearing as home or guest team in a league (which is the key) reducing them in a way, that the team only appears once in the value-array.

I try around this day, maybe I'll find a solutin, but help is appreciated... Kind regards, Steffen

dready92 commented 13 years ago

Hello,

I don't really see the difficulty doing this : the reduce function is the perfect tool for those kind of queries.

First your map function should contain the "clubX" info, so emit it as the value :

function (doc) {
    if ........
        emit ( [doc.thing1, doc.thing2, doc.thing3], doc.clubName );
}

Then the reduce function will look like :

function(keys,values,rereduce) {

    var back = [];

    // helper fn to only push non already present values
    var pushUnique = function ( oneArray ) {
        oneArray.forEach( function(v) {
                if ( back.indexOf(v) < 0 )    back.push(v);
            });
    };

    if ( !rereduce ) {
        // keys[x][0] contains the emitted key, values[x] the associated value
        // so values could look like : [ "club3", "club56" ]
        pushUnique(values);
    } else {
        // values[x] contains ie ["club1", "club4"]
        values.forEach( function( arrayFromReduce ) {
            pushUnique(arrayFromReduce);
        });
    }
    return back;
}

Hope you get the idea. I highly suggest you read the dedicated wiki page @ http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views . Also as this has little to do with PoC I think the CouchDB users mailing list is the place to ask this type of questions, you'll find the help you need : the couch community is awesone you won't be disapointed.

Regards,

Mickael