Search code examples
node.jscassandracqlshnosql

Using nodejs 'cassandra-driver' prepared query with IN query


This is a potential newbie question but I couldn't find an answer out in the wild.

I'm currently building a simple user event log of this form (some attributes elided to keep this simple):

CREATE TABLE events.by_hour (
  level tinyint, /* 60 = FATAL, 10 = TRACE */
  hour int, /*  in YYYYMMDDHH format */
  insertion_time timeuuid,
  userid TEXT,
  message TEXT,
PRIMARY KEY ((type,hour),userid,insertion_time))
WITH CLUSTERING ORDER BY (userid ASC, insertion_time ASC);

I would like to make a prepared query to fetch all events optionally filtered by a given user over some set of levels ideally over the course of several hours.

I can easily build a query that queries a single level and hour:

var cassandra = require('cassandra-driver');
var client = new cassandra.Client({contactPoints: ['127.0.0.1']});

var query 
    = 'SELECT * FROM events.by_hour 
      WHERE level IN (?) and hour IN (?) and userid = ?;';

var options = [ 10, 2016032117,'user_uuid' ];

client.execute(query, options, {
                    prepare: true
                }, function (err, result) {
                    // Do stuff... 
                    next(err);
                });

This works fine for a single hour and level. I would love to specify multiple hours and levels in the above query but playing with the code I'm unable to get that to work either by specifying the set as a string or as an array of values.

I think I'm forced to do something like this:

Build the query based upon the number of levels and hours are needed:

// for 1 level and 2 hours:
query = 'SELECT * FROM events.by_hour 
      WHERE level IN (?) and hour IN (?,?) and userid = ?;';

options = [ 10, 2016032117,2016032118,'user_uuid' ];

client.execute(query, options, {
                    prepare: true
                }, function (err, result) {
                    // Do stuff... 
                    next(err);
                });

// for 2 levels and 2 hours:
query = 'SELECT * FROM events.by_hour 
      WHERE level IN (?,?) and hour IN (?,?) and userid = ?;';

options = [ 10, 20, 2016032117,2016032118,'user_uuid' ];

client.execute(query, options, {
                    prepare: true
                }, function (err, result) {
                    // Do stuff... 
                    next(err);
                });

I don't love this. BUT I can still get the benefits of prepared queries even here since we can just pass in 'prepared: true'. It feels like there should be a better way... but I'm not sure what I'm trying to do is even possible with single prepared query.

Can anyone lend some wisdom here?

Thanks!


Solution

  • You should use the IN operator followed by the query marker (no parenthesis) and provide the parameter for the query marker as an array:

    const query = 'SELECT * FROM events.by_hour WHERE level IN ? and ' + 
                  'hour IN ? and userid = ?';
    const params = [ [ 10, 20, 30] , [ 2016032117, 2016032118 ],'user_uuid' ];
    client.execute(query, params, { prepare: true }, callback);