1

I'm trying to write a query that in SQL would look something like:

select * from WorkOrder wo
    where wo.userId = 1
    and wo.isSynced = 0
    and wo.status in ('COMPLETE', 'REJECTED', 'SUSPENDED_NO_ACCESS', 'SUSPENDED_OTHER');

I've added an index on userId, isSynced, and status.

If I build a query like the following it works as long as I only filter on 2 different status values. As soon as I add 3 or more it doesn't return any results. Am I doing something wrong or do I need to approach this in a totally different way?

//this works
var keyRange = ydn.db.KeyRange.bound([userId, 0, Status.Complete],
            [userId, 0, Status.REJECTED]);
//this doesn't work
var keyRange = ydn.db.KeyRange.bound([userId, 0, Status.Complete],
            [userId, 0, Status.Suspended_AccessUnavailable],
            [userId, 0, Status.REJECTED]);


var iterator = new ydn.db.IndexValueIterator(Store.WorkOrder, 'userId, isSynced, status', keyRange);

return db.values(iterator)
gusgorman
  • 170
  • 1
  • 11

1 Answers1

1

Currently multi-query ("IN') and self-join ("AND") are manual and require a lot of boilerplate to do those. For complex query like in this case, will require in-memory sorting using ydn.structs.Buffer.

Use sorted merge or zigzag merge for self join.

Use multiple cursors for multi-query. Briefly as follow:

var iters = [];
var keys = ['COMPLETE', 'REJECTED', 'SUSPENDED_NO_ACCESS', 'SUSPENDED_OTHER'];
for (var i = 0; i < keys.length; i++) {
  iters[i] = ydn.db.IndexValueIterator.where('WorkOrder', 'status', '=', keys[i]);
});
var results = [];
db.scan(function(cursors) {
   // here we have four cursors for respective four index keys.
   // calculate lowest key(s) and put into result
   var min_i = ...
   results.push(cursors[i].getValue());
   // prepare next cursor iteration, 
   var next_position = [];
   next_position[min_i] = true; // advance lowest cursor to next position, while keeping the rest of cursor hold in current position.
   return next_position;
}, iters, 'readonly', ['WorkOrder']).then(function() {
   // use results
   console.log('results', results);
}, function(e) {
   console.error(e.stack);
});

It is not difficult to make a wrapper for the above code so that, the library will eventually support like:

 var query = db.from('WorkOrder').where('status', 'in', ['COMPLETE', 'REJECTED', 'SUSPENDED_NO_ACCESS', 'SUSPENDED_OTHER']);
 query.list().then(function() {
   // use results
   console.log('results', results);
}, function(e) {
   console.error(e.message);
});
Kyaw Tun
  • 12,447
  • 10
  • 56
  • 83
  • Thankyou for the reply. To be honest I didn't understand all of it so I have just executed multiple queries and then merged the results in memory. – gusgorman Sep 16 '14 at 15:05
  • Sorry to labour the point... but is this a typical problem with no-sql databases? I don't consider this to be a complex query at all... would it be possible if I was using IndexedDb directly rather than going through a wrapper library? – gusgorman Sep 18 '14 at 08:26