How do I query a tstzrange with Sequelize? - node.js

I have a range of timestamp with timezone stored in one column of my PostgreSQL database, e.g:
timeRange (tstzrange)
["2019-02-10 23:00:00+00","2019-03-09 23:00:00+00")
I want to query my database based on that column, testing if a given date range is contained by the range in my column.
According to the PostgreSQL docs, I can query a range contained by another range with the <# operator:
Operator | Description | Example | Result
<# | range is contained by | int4range(2,4) <# int4range(1,7) | t
According to the Sequelize docs, this can be done using the operator $contained:
$contained: [1, 2] // <# [1, 2) (PG range is contained by operator)
I have tried querying using this operator:
const start = '2019-02-11T00:30:00.000Z';
const end = '2019-02-08T02:30:00.000Z';
MyModel.findOne({
where: {
timeRange: {
$contained:
[
new Date(start),
new Date(end)
]
}
}
});
This doesn't work and gets the error
error: operator does not exist: tstzrange = timestamp with time zone
The query looks like this
'SELECT * FROM "model" AS "model" WHERE "model"."timeRange" = \'2019-06-26 22:00:00.000 +00:00\'::timestamptz;'
This probably explains why I got the PostgreSQL error. How can I properly format the query to get what I want?

Using this similar question, I figured out a workaround but I'm not sure why or how it works : Query with date range using Sequelize request with Postgres in Node
var Sequelize = require('sequelize');
const Op = Sequelize.Op;
const start = '2019-02-11T00:30:00.000Z';
const end = '2019-02-08T02:30:00.000Z';
MyModel.findOne({
where: {
timeRange: {
[Op.contained]:
[
new Date(start),
new Date(end)
]
}
}
});
If anyone has an explanation, I would be happy to hear it

Related

Can't use variables as key, value for mongoose .find()

I'm using mongoose 5.11.4 and trying to find documents. On the official docs they say
MyModel.find({ name: /john/i })
I wanna know how to use variables for "name" & "john" and get the exact thing done. this is an API that I'm working on. filter (name) and the value (john) gonna decide by the frontend user. We should search for a given field using the value. Any suggestions?
let filter = req.params.filter
let value = req.params.value
MyModel.find({ filter : /value/i })
doesn't work
You can use the RegExp object to convert the value to a regular expression.
let regex = new RegExp(`${value}`,'options');
Now you can use it on mongoose query.
model.find({name:regex});
this worked : )
let filter = req.params.filter
let value = req.params.value
const filterParam = {}
filterParam[filter] = { $regex: .*${value}.* }
const suppliers = await Supplier.find(filterParam)

Mongoose, NodeJS & Express: Sorting by column given by api call

I'm currently writing a small API for a cooking app. I have a Recipe model and would like to implement sorting by columns based on the req Parameter given.
I'd like to sort by whatever is passed in the api call. the select parameter works perfectly fine, I can select the columns to be displayed but when I try to sort anything (let's say by rating) the return does sort but I'm not sure what it does sort by.
The code i'm using:
query = Recipe.find(JSON.parse(queryStr));
if(req.query.select){
const fields = req.query.select.split(',').join(' ');
query = query.select(fields);
}
if(req.query.sort){
const sortBy = req.query.sort.split(',').join(' ');
query = query.sort({ sortBy: 1 });
} else {
query = query.sort({ _id: -1 });
}
The result, when no sorting is set: https://pastebin.com/rPLv8n5s
vs. the result when I pass &sort=rating: https://pastebin.com/7eYwAvQf
also, when sorting my name the result is also mixed up.
You are not using the value of sortBy but the string "sortBy". You will need to create an object that has the rating as an object key.
You need the sorting object to look like this.
{
rating: 1
}
You can use something like this so it will be dynamic.
if(req.query.sort){
const sortByKey = req.query.sort.split(',').join(' ');
const sortByObj = {};
sortByObj[sortByKey] = 1; // <-- using sortBy as the key
query = query.sort(sortByObj);
} else {
query = query.sort({ _id: -1 });
}

Node Js sequelize select query by month

Am new in Node Js, In my Node Js project am using sequelize ORM with MySql database.
This is my query i want to write select query by month.
This is my query SELECT * FROM cubbersclosure WHERE MONTH(fromDate) = '04'
Here fromDate field type is date
This my code:
var fromDate = '2019-04-01'
var fromDateMonth = new Date(fromDate);
var fromMonth = (fromDateMonth.getMonth()+ 1) < 10 ? '0' + (fromDateMonth.getMonth()+1) : (fromDateMonth.getMonth()+1);
CubbersClosure.findAll({
where:{
// select query with Month (04)... //fromMonth
}
}).then(closureData=>{
res.send(closureData);
}).catch(error=>{
res.status(403).send({status: 'error', resCode:200, msg:'Internal Server Error...!', data:error});
});
Here fromMonth get only month from date, so i want to write code select query by month.
I'm not sure but what about try this?
where: {
sequelize.where(sequelize.fn("month", sequelize.col("fromDate")), fromMonth)
}
for those of you looking for postgres, this is a somewhat hacky way to make this work (make sure to unit test this):
const results = await models.users.findAll({
where: this.app.sequelize.fn('EXTRACT(MONTH from "createdAt") =', 3)
});
you can also take this a step further and query multiple attributes like so:
const results = await models.table.findAll({
where: {
[Op.and] : [
this.app.sequelize.fn('EXTRACT(MONTH from "createdAt") =', 3),
this.app.sequelize.fn('EXTRACT(day from "createdAt") =', 3),
]
}
});

SQL Server : lower camelcase for each result

I am creating an API with SQL Server as the database. My tables and columns are using Pascal case (CountryId, IsDeleted, etc) that cannot be changed.
So when I do this:
const mssql = require('mssql');
var sqlstr =
'select * from Country where CountryId = #countryId';
var db = await koaApp.getDb();
let result = await db.request()
.input('countryId', mssql.Int, countryId)
.query(sqlstr);
My resulting object is
{
CountryId: 1,
CountryName: "Germany"
}
But I want it to be
{
countryId: 1,
countryName: "Germany"
}
I know there is a "row" event, but I wanted something more performant (since I may be returning several rows from the query, above is just an example).
Any suggestions?
PS: I want to avoid the FOR JSON syntax
Posting this as an actual answer, as it proved helpful to the OP:
if it's viable, you may try simply specifying the columns in the query as such:
select
CountryID countryId,
CountryName countryName
from
Country
where
CountryId = #countryId
Typically it's not best practice to use select * within queries anyways because of performance.
A simple explanation, putting a space and a new name (or perhaps better practice, within square brackets after each column name, such as CountryName [countryName] - this allows for characters such as spaces to be included within the new names) is aliasing the name with a new name of your choosing when returned from SQL.
I'd suggest using the lodash utility library to convert the column names, there is a _.camelCase function for this:
CamelCase documentation
_.camelCase('Foo Bar');
// => 'fooBar'
_.camelCase('--foo-bar--');
// => 'fooBar'
_.camelCase('__FOO_BAR__');
// => 'fooBar'
You can enumerate the result keys using Object.entries then do a reduce, e.g.
let result = {
CountryId: 1,
CountryName: "Germany"
};
let resultCamelCase = Object.entries(result).reduce((obj,[key,value]) => {
obj[_.camelCase(key)] = value;
return obj;
}, {});
console.log(resultCamelCase);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

collection.find on an item in a subarray

I have the following Object Structure:
[
{
name: "someThing"
,securities: [ {"id": "2241926"} ]
}
]
I want to be able to return all objects in the outer array, that has at least one child secuirty with an id that starts with a value. I have tried a few things and keep running up short. On the mongoo console, this query works:
db.caseSummary.find({"securities.id": /^224.*/i})
We are using ES6, so please apologies for the generator syntax:
const q = require("q");
const startsWith = function(term){
return new RegExp('^' + term + '.*', 'i')
}
const find = function*(collection, criteria){
const command = q.nbind(collection.find, collection),
myCriteria = criteria || {},
results = yield command(myCriteria),
toArray = q.nbind(results.toArray, results) ;
return yield toArray()
}
const searchBySecurity = function*(mongo, term) {
const collection = mongo.collection("caseSummary"),
criteria = {"securities.id": startsWith(term) };
return yield find(collection, criteria);
}
so searchBySecurity(this.mongo, '224') It returns an empty array, it should return the same results as the mongo console. I guess I am missing a pretty basic concept in translating my search criteria or invoking the find writing this in node from raw mongo console query.
Edit 1: to be clear I want to return all parent objects, which have subarrays that contain a value that starts with the term passed in...
Edit 2:
I changed the criteria to be:
criteria = { "securities": {
"$elemMatch": {
"id": "901774109" //common.startsWith(term)
}
}
};
Still the same results.
Edit 3:
Using nodejs - mongodb "version": "1.4.38"
Edit 4:
this ended up not being an issue

Resources