Diego
Diego

Reputation: 65

CouchDB null value when sort descending

I have CouchDB view that gives me a correct value in natural order and a null when sorted descending, here are the Futon screenshots:

Natural order

Descending order

Here is the view code:

"informe_precios": {
           "map": "function(doc){if(doc.doc_type=='precio'){emit([doc.comprador,doc.fecha.substr(0,4),doc.fecha.substr(5,2)],{precio:doc.precio,litros:doc.litros});}}",
           "reduce": "function(keys, values, rereduce){var importe= 0; var totallitros = 0;for(var i = 0; i < values.length; i++) {importe += values[i].precio*values[i].litros;totallitros += values[i].litros;}return importe/totallitros;}"
       }

I need it descending because I want to get 12 last values.

TIA Diego

Upvotes: 2

Views: 497

Answers (1)

smathy
smathy

Reputation: 27961

You're always assuming that your reduce function is called with the output of your map function, ie. you're not handling the rereduce situation.

In the rereduce your values will be the importe/totallitros values from previous reduce calls.

Your reduce function is getting a "price per liter" average for each month, so because it's an average there's no way for your rereduce function to actually handle that data because for the multiple values coming in there's no way to know their weight in the average.

So, you'll need to change your function to return the count so that you can use that to weight the average in the rereduce function (we're also using the inbuilt sum function to make things simpler):

function(keys, values, rereduce) {
  if (rereduce) {
    var length = sum(values.map(function(v){return v[1]}));
    var avg = sum(values.map(function(v){
      return v[0] * (v[1] / length)
    }));
    return [avg, length];
  }
  else {
    var importe= 0;
    var totallitros = 0;
    for( var i = 0; i < values.length; i++) {
      importe += values[i].precio * values[i].litros;
      totallitros += values[i].litros;
    }
    return [ importe/totallitros, values.length ];
  }
}

The final result you'll see in your view here will be an array, so you'll always need to pick out the first element of that in your client code.

Upvotes: 1

Related Questions