PouchDB query using parameters
Asked Answered
F

4

7

Lets suppose we store cars (about 40MB) represented as JSON objects in a PouchDB, and we would like to search, based on the horsepower attribute. example in sql: select * from cars where HP > 100.

You can query pouchDB by key, but obviously HP is not the key of the document. Is there a way you can do this?

As far as I understand the map function,

function(doc) {
  if(doc.value) {
    emit(doc.value, null);
  }
}

it is not possible to access any variable within the outer scope of the function.

var horsePower = $scope.horsePowerInputField

function(doc) {
  if(doc.hp > horsePower) {
    emit(doc.value, null);
  }
}

so is there a possibility to query the database, parametrized based on non-key variables?

Forestall answered 22/12, 2013 at 13:31 Comment(0)
S
9

As of PouchDB 2.0.0, closures in map/reduce queries are supported. Details here.

However, you should probably avoid them if you can, because

  1. They're not supported by CouchDB, only PouchDB
  2. Saved map/reduce views, which are much faster and will probably be added in 2.1.0, cannot support closures.

That being said, if you do want to use closures, you can now do this:

var horsePower = $scope.horsePowerInputField

function(doc, emit) { // extra 'emit' tells PouchDB to allow closures
  if(doc.hp > horsePower) {
    emit(doc.value, null);
  }
}
Satang answered 21/3, 2014 at 21:12 Comment(0)
W
3

Your map function loses its closure because it is re-evaluated inside of PouchDB (that's how it gets the emit function). This means you can't access any variables from your code, but you can still query the database.

In PouchDB, views are not persistent, so your query always looks at every document in the database, and you have to do the filtering after the map function. Something like this:

function findCars(horsePower, callback) {
  // emit car documents
  function map(doc) {
    if(doc.type == 'car' && doc.value) {
      emit(doc.value, null);
    }
  }

  // filter results
  function filter(err, response) {
    if (err) return callback(err);

    var matches = [];
    response.rows.forEach(function(car) {
      if (car.hp == horsePower) {
        matches.push(car);
      }
    });
    callback(null, matches);
  }

  // kick off the PouchDB query with the map & filter functions above
  db.query({map: map}, {reduce: false}, filter)
}

Is one way to solve this problem. Pouch will iterate over each document, passing it to your map function. When done, filter gets called with an array of all the emitted documents. filter does not lose its closure context, so you can filter the results based on horsepower or any other field here.

Whisler answered 23/12, 2013 at 19:21 Comment(0)
A
2

It's better not to use closures. Do this instead:

var horsePower = $scope.horsePowerInputField;
db.query(function(doc) {emit(doc.hp)}, {startkey: horsePower, include_docs: true});
Airwaves answered 28/10, 2014 at 20:10 Comment(0)
M
0

You can use a global variable trick

var getTimesheetId = '';  //global Variable
var getOfflineTimesheet= function(documentId){
getTimesheetId = documentId;   // assigning the value of the parameter to the global variable


var map= function(doc){
        if(doc.timesheet){
            console.log(getTimesheetId);   // here the map function is able to get the value of the global variable, which is essentially the parameter.
            if (doc._id == getTimesheetId){ 
                emit(doc._id, doc.timesheet);
            }
        }
    };

db.query({map: map}, function(err, res){
        if(!err){
            var out= "";
            res.rows.forEach(function(element){
                console.log(element.value);
            });

        }
    })
  };

And the way you will call it is

getOfflineTimesheet('timesheet1DocId'); getOfflineTimesheet('timesheet2DocId'); getOfflineTimesheet('timesheet3DocId');

Mucronate answered 25/2, 2014 at 23:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.