0

I want to filter an array of objects based on a query string provided by the user in Node.js. There are packages such as rql or orql that can achieve this, but they seem to have problem with strings containing colon, such as time stamps. The code using rql:

var rql = require("rql/js-array");
var query1 = "time=lt=2018-08-06";
var query2 = "time=lt=2018-08-06T13:45:36.000Z"

var products = [
 {price:14.99, rating: 5, time: "2018-08-04T13:45:36.000Z"},
 {price:5.99, rating: 3, time: "2018-08-05T13:45:36.000Z"},
 {price: 16.5, rating:2, time: "2018-08-06T13:45:36.000Z"}];

console.log(rql.query(query1, {}, products)); // works
console.log(rql.query(query2, {}, products)); // gives error

The error message:

URIError: Unknown converter 2018-08-06T13
at stringToValue (/home/runner/node_modules/rql/parser.js:186:10)
at /home/runner/node_modules/rql/parser.js:99:20
at String.replace (<anonymous>)
at parse (/home/runner/node_modules/rql/parser.js:71:33)
at Object.query (/home/runner/node_modules/rql/js-array.js:358:10)

Similarly in orql:

var orql = require('orql');

var query1 = "time=lt=2018-08-06";
var query2 = "time=lt=2018-08-06T13:45:36.000Z"

var products = [
  {price:14.99, rating: 5, time: "2018-08-04T13:45:36.000Z"},
  {price:5.99, rating: 3, time: "2018-08-05T13:45:36.000Z"},
  {price: 16.5, rating:2, time: "2018-08-06T13:45:36.000Z"}];

console.log(orql(products, query1)); // works
console.log(orql(products, query2)); // gives error

The error message:

TypeError: Cannot read property 'name' of null
at rqlNodeToFunc (/home/runner/node_modules/orql/index.js:351:20)
at Function.rql.compile (/home/runner/node_modules/orql/index.js:65:14)
at rql (/home/runner/node_modules/orql/index.js:48:14)

Any idea how to do query on arrays of objects with timestamps?

3 Answers 3

1

Try using Lodash.

npm install lodash --save

Filter by date:

_.filter(products, function(element) { return element.time.includes('2018-08-04') })

Filter between dates:

let startDate = new Date('08/01/2018');
let endDate = new Date('08/06/2018');

_.filter(products, function (element) {
    let date = new Date(element.time);
    return date >= startDate && date <= endDate;
});

See it in action.

To get only one result use _.find instead of _.filter.

Sign up to request clarification or add additional context in comments.

2 Comments

But can it do flexible queries, e.g. values between a and b? And can it be provided as a query by the user?
I've updated the answer with the code to find between dates. You could do what you want but providing your own logic. If you want to write SQL queries this is not the solution.
0

Seems like it's a bug in the rql parser, because the documentation says it supports "ISO UTC format without colon encoding":

Values in queries can be strings (using URL encoding), numbers, booleans, null, undefined, and dates (in ISO UTC format without colon encoding).

You can solve it adding the word string before the date.

var query2 = "time=lt=string:2018-08-06T13:45:36.000Z"

Or also encoding the colon (replacing it by %3A):

var query2 = "time=lt=2018-08-06T13%3A45%3A36.000Z";

1 Comment

It works! Amazing! Can you explain what was/is happening? I could not find anything in the documentation.
0

Javascript also has filter method. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

var products = [
 {price:14.99, rating: 5, time: "2018-08-04T13:45:36.000Z"},
 {price:5.99, rating: 3, time: "2018-08-05T13:45:36.000Z"},
 {price: 16.5, rating:2, time: "2018-08-06T13:45:36.000Z"}
];

const byRating = function(rating) {
  return products.filter(product => product.rating === rating)
}

const withRatingFive = byRating (5); // 5 can be a parameter from your users.

const priceLowerThan = function(price) {
  return products.filter(product => product.price < price)
}

const cheapestProduct = priceLowerThan(6); // 6 can be a parameter from your users.

const dateBetween = function(start,end) {
  return products.filter(product => (product.time >= start && product.time <= end))
}

Just some examples that could help you in the right direction.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.