How to fetch data using between with two columns in sequelize - node.js

Please help me to write sequelize function for below MYSQL query
select * from userCategory where 25 between minAge and maxAge;
A Table looks like below
userRecords
id minAge maxAge category
1 11 20 category 1
2 21 30 category 2
Thanks in advance

You cannot simply use BETWEEN as it requires a column name or a computed table (like WITH) for the left side of the SQL function
The simplest solution would be:
models.userCategory.findAll({
where: {
minAge: { [Op.lt]: 25 },
maxAge: { [Op.gt]: 25 },
},
})
If you must use BETWEEN then sequelize will make your life much harder, as you will require to use sequelize.literal('SELECT 25 as age') to start with in order to have a pseudo table ... just so you can use BETWEEN?

Related

retrieve all whose `date` is within last 6 minutes

I have a Product collection stored in MongoDB. It has a attribute date :
const productSchema = new mongoose.Schema<ProductAttrs>({
date: {
type: Date,
required: true,
}
...
})
I would like to retrieve all products whose date is within last 6 minutes comparing with current time. What is the efficient way to retrieve that in mongoose ?
I am using express.js + typescript + mongoose v5.11 in my project.
You must use Mongoose to search every record where the time is greater than now - 6 minutes.
I have no way to test it, but the query should look something like this:
const sixMinutes = (6*60*1000); // 6 minutes
let sixMinutesAgo = new Date();
sixMinutesAgo.setTime(sixMinutesAgo.getTime() - sixMinutes);
const products = Product.find({
date: {
$gte: sixMinutesAgo
}
})
If your MongoDB server version is 5.0 you could use the new operator $dateDiff. In this case it is very handy and you do not even need an aggregate:
db.collection.find({
"$expr": {
"$lte": [
{
"$dateDiff": {
startDate: "$date",
endDate: new Date(),
unit: "minute"
}
},
6
]
}
})
It allows you to specify the unit field, which makes the query very straightforward in my opinion.
$expr evaluates an expression and returns true or false, just that. If the expression result is true then the row is returned, otherwise it is not.
$lte means less than or equal (the <= operator) and it returns true only when the first argument is less than or equal the second operator. Basically, this is what it does in pseudocode:
foreach doc in collection
if (minute)(currentDate - document.date) <= 6 then
return document

Adonis Lucid ORM: How do I change the datetime to a date only and then use the .distinct()

I have a table called Orders
Here is a sample values of that table:
[
{
id: 1,
delivery_date: 2020-06-01 00:00:00,
quantity: 2
},
{
id: 2,
delivery_date: 2020-06-01 01:00:00,
quantity: 2
},
]
I now queried this
...
await Order
.query()
.select('delivery_date')
.distinct('delivery_date')
.fetch()
The .distinct() did not work because the time is not the same, so my question is how do I use distinct to work even though the time is not the same and the date is the same? and I also need to return the date only, without the time
So what I did is just separate the date and the time. As per the project requirements I think that was the best solution for me, not sure why, but adonis was still adding the time on my date, I think it was moment under the hood, so to solve that;
You have to let Adonis know that your column is a date first by adding this on your model, add your column name inside that array:
static get dates () {
return super.dates.concat(['delivery_date'])
}
After that we need to format that column when displaying the data by using castDate
static castDates(field, value) {
if (field === 'delivery_date') {
return value.format('YYYY-MM-DD')
}
return super.formatDates(field, value)
}
Note also that you have to call .fetch() for that to work
All this are on the documentation:
https://adonisjs.com/docs/4.1/lucid#_dates

Increment a column with the default value as null

I need to increment a column with 1 on some occasions, but the default value of that column is null and not zero. How do I handle this case using sequelize? What method could be utilized?
I could do by checking the column for null in one query and updating it accordingly in the second query using sequelize but I am looking for something better. Could I handle this one call?
I'll confess that I'm not terribly experienced with sequelize, but in general you'll want to utilize IFNULL. Here's what the raw query might look like:
UPDATE SomeTable
SET some_column = IFNULL(some_column, 0) + 1
WHERE <some predicate>
Going back to sequelize, I imagine you're trying to use .increment(), but judging from the related source, it doesn't look like it accepts anything that will do the trick for you.
Browsing the docs, it looks like you might be able to get away with something like this:
SomeModel.update({
some_column: sequelize.literal('IFNULL(some_column, 0) + 1')
}, {
where: {...}
});
If that doesn't work, you're probably stuck with a raw query.
First you need to find the model instance and update via itself, or update directly via Sequelize Static Model API.
Then you'll check whether the updated field got nullable value or not ? If fails then do the manual update as JMar propose above
await model.transaction({isolationLevel: ISOLATION_LEVELS.SERIALIZABLE}, async (tx) => {
const user = await model.User.findOne({
where: {
username: 'username',
},
rejectOnEmpty: true,
transaction: tx,
});
const updatedRecord = await user.increment(['field_tag'], {
transaction: tx,
});
if (!updatedRecord.field_tag) {
/** Manual update & Convert nullable value into Integer !*/
await model.User.update({
field_tag: Sequelize.literal('IFNULL(field_tag, 0) + 1')
}, {
where: {
username: 'username',
},
transaction: tx,
});
}
});

Distinct count with sequelize

I'm trying to get a distinct count with sequelize such as
'SELECT COUNT(DISTINCT(age)) AS `count` FROM `Persons` AS `Person`'
As long as I use a raw query, I get the desired result. However, as soon as I change to the sequelize count function, the query is broke in Postgres:
Person.count({distinct:'age'}).then(...);
results to
'SELECT COUNT(DISTINCT(*)) AS `count` FROM `Persons` AS `Person`'
which leads to a syntax error. Solutions described in different posts such as How to get a distinct count with sequelize? do not work, unless you add an include statement or a where clause which I do not have in this special case.
Does anybody know a proper solution for this?
You have to use Sequelize aggregation to make it worked correctly.
Model.aggregate(field, aggregateFunction, [options])
Returns: Returns the aggregate result cast to options.dataType, unless
options.plain is false, in which case the complete data result is
returned.
Example:
Person.aggregate('age', 'count', { distinct: true })
.then(function(count) {
//.. distinct count is here
});
Executing (default):
SELECT count(DISTINCT("age")) AS "count" FROM "persons" AS "person";
You can do it something like this :
models.User.findAll({
attributes: ['user_status',[sequelize.fn('COUNT', sequelize.col('user_status')), 'total']] ,
group : ['user_status']
});
That will return something like :
[
{ user_status : 1 , total : 2 },
{ user_status : 2 , total : 6 },
{ user_status : 3 , total : 9 },
...
]
Then you can loop through returned data and check of status
In latest version, you should be doing
Person.count({distinct:true, col: 'age'}).then(...);
See: http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-count

CouchDB view map function that doesn't segregate reduce keys

Here is the doc "schema":
{
type: "offer",
product: "xxx",
price: "14",
valid_from: [2012, 7, 1, 0, 0, 0]
}
There are a lot of such documents with many valid dates in the past and the future and a lot of times two or three offers in the same month. I can't find a way to make the following view: Given a date, give me a list of the products and their running offer for that date.
I think I need to emit the valid_date field in order to set the endkey of the query to the given date and then I need to reduce on the max of this field, which means i can't emit it.
Have I got it wrong? I am totally new to the map/reduce concept. Any suggestions on how to do it?
I'm really thrown by your comments about wanting to reduce, based on your requirements you want just a map function - no reduce. Here's the map function based on what you asked for:
function(d) {
if( d.type === 'offer' ) {
var dd = d.valid_from;
dd[1] = ( '0' + ( dd[1] + 1 )).slice(-2); // remove the +1 if 7 is July not August
dd[2] = ( '0' + dd[2] ).slice(-2);
emit( dd.slice(0,3).join('-') );
}
}
Then to show all offers valid for a given day you'd query this view with params like:
endkey="2012-08-01"&include_docs=true

Resources