Sequelize - case-insensitive like - mysql

How can I achieve this in Sequelize?
SELECT * FROM table where lower(column) LIKE ('abcd%');
I can't find a way to mix lower function with $like

You should use Sequelize.Op :
Table.findAll({
where: {
name: {
[Sequelize.Op.iLike]: searchQuery
}
}
})
Don't forget to add % before or after your searchQuery, if you want to make a partial query.
See the docs here

I found the solution:
Table.findAll({
attributes: ['createdAt', 'col'],
where: {
$and:[
{
createdAt:{
$between:[minDate, maxDate]
}
},
Sequelize.where(
Sequelize.fn('lower', Sequelize.col('col')),
{
$like: 'abcd%'
}
)
]
}
});

If you're using PostGres, you can use the $iLike operator to search rows (NOT column names like your question asks).
Sequelize Docs
While it doesn't fully address your question, hopefully it will help someone down the road who searches for case-insensitive + Sequelize, which brought me here.
Table.findAll({
where: {
createdAt: {
$between: [minDate, maxDate]
},
someOtherColumn: {
$like: '%mysearchterm%'
}
}
})

I run into similar problem and solved by
const values = ['adcd'].map(x => x.toLowerCase());
const results = await SomeModel.findAll({
attributes: [
...Object.keys(SomeModel.rawAttributes),
[Sequelize.fn('LOWER', Sequelize.col('someColumn')), 'lower'],
],
having: { lower: values, },
});

Related

LEFT() function extracts a number of characters from a string inside where

How can build this query?
In the documentation I didn't find any reference to the LEFT function :(
SELECT *
FROM Customers
WHERE
LEFT(CustomerName, 2) = 'An';
to:
await Customers.findOne({
where: {
[fn('left', col('CustomerName'), 2)]: 'An'
}
});
Any idea?
I think you can do:
await Customers.findOne({
where: {
CustomerName: {
[Op.startsWith] : 'An'
}
}
});

Check if an user exist in my database with Node and MySQL [duplicate]

I need to check if entry with specific ID exists in the database using Sequelize in Node.js
function isIdUnique (id) {
db.Profile.count({ where: { id: id } })
.then(count => {
if (count != 0) {
return false;
}
return true;
});
}
I call this function in an if statement but the result is always undefined
if(isIdUnique(id)){...}
I don't prefer using count to check for record existence. Suppose you have similarity for hundred in million records why to count them all if you want just to get boolean value, true if exists false if not?
findOne will get the job done at the first value when there's matching.
const isIdUnique = id =>
db.Profile.findOne({ where: { id} })
.then(token => token !== null)
.then(isUnique => isUnique);
Update: see the answer which suggests using findOne() below. I personally prefer; this answer though describes an alternative approach.
You are not returning from the isIdUnique function:
function isIdUnique (id) {
return db.Profile.count({ where: { id: id } })
.then(count => {
if (count != 0) {
return false;
}
return true;
});
}
isIdUnique(id).then(isUnique => {
if (isUnique) {
// ...
}
});
You can count and find.
Project
.findAndCountAll({
where: {
title: {
[Op.like]: 'foo%'
}
},
offset: 10,
limit: 2
})
.then(result => {
console.log(result.count);
console.log(result.rows);
});
Doc link, v5 Beta Release
I found the answer by #alecxe to be unreliable in some instances, so I tweaked the logic:
function isIdUnique (id, done) {
db.Profile.count({ where: { id: id } })
.then(count => {
return (count > 0) ? true : false
});
}
As Sequelize is designed around promises anyway, alecxe's answer probably makes most sense, but for the sake of offering an alternative, you can also pass in a callback:
function isIdUnique (id, done) {
db.Profile.count({ where: { id: id } })
.then(count => {
done(count == 0);
});
}
}
isIdUnique(id, function(isUnique) {
if (isUnique) {
// stuff
}
});
Extending #Jalal's answer, if you're very conscious about performance implications while maintaining a simple Sequelize structure and you do not need the row data, I suggest you only request one column from the database. Why waste bandwidth and time asking the database to return all columns when you won't even use them?
const isIdUnique = id =>
db.Profile.findOne({ where: { id }, attributes: ['id'] })
.then(token => token !== null)
.then(isUnique => isUnique);
The attributes field tells Sequelize to only request the id column from the database and not sending the whole row's content.
Again this may seem a bit excessive but at scale and if you have many columns that hold a lot of data, this could make a giant difference in performance.
Try the below solution. I tried it and it works well.
const isIdUnique = async (id, model) => {
return await model.count({ where: { id: id } });
};
const checkExistId = await isIdUnique(idUser, User);
console.log("checkExistId: ", checkExistId);

React: Reaching Nested State Items w/ Reducer

I'm working with some deeply nested state objects, and thanks to a lot of wisdom from the SO community, have switched to useReducer to manage the state. I can't figure out the syntax to reach deeply nested items or consecutive objects in arrays. Here's my state object:
const initialState = {
customer: [
{
name: "Bob",
address: "1234 Main Street",
email: "bob#mail.com",
phone: [
{
mobile: "555-5555",
home: "555-5555"
}
]
},
{
name: "Reggie",
address: "5555 Pineapple Lane",
email: "reggie#mail.com",
phone: [
{
mobile: "123-4567",
home: {
fax: "444-4444",
evening: "222-2222"
}
}
]
}
]
}
I need to reach our second customer, Reggie, and change both his address and home evening phone number (customer[1].address & customer[1].phone[1].home.evening)
I've tried this with my useReducer case statements, but no luck. . .I get a TypeError: Cannot read property 'object' of undefined when I call on these functions (presumably from my dropdown menu, who's value is set to this props I'm trying to change):
case "SET_CUST1_ADDRESS":
return {
...state,
customer: [
{ ...state.customer[1], address: value }
]
};
onChange={({ target: { value } }) =>
dispatch({ type: "SET_CUST1_ADDRESS", value })
}
And the second for the evening number. . .
case "SET_CUST1_PHONE_HOME_EVENING":
return {
...state,
customer: [
{
...state.customer[1],
phone: [
{
...state.customer[1].phone[0],
home: {
...state.customer[1].phone[0].home,
evening: value
}
}
]
}
]
};
onChange={({ target: { value } }) =>
dispatch({ type: "SET_CUST1_PHONE_HOME_EVENING", value
})
}
I understand the need to work with flattened state objects to make all this much easier, but unfortunately the data structure I'm working with is immutable. Tips/tricks/comments welcome. Thanks!
UPDATE:
It seems there is an unresolved conflict between using these two case statements, which is causing the TypeError: Cannot read property 'object' of undefined during my state changes. When I try to change the state of two different array objects in the same array, I get the error. Apparently these two cases cannot exist simultaneously:
case "SET_CUST_ADDRESS":
return {
...state,
customer: [
{ ...state.customer[0], address: value }
]
};
case "SET_CUST1_ADDRESS":
return {
...state,
customer: [
state.customer[0],
{ ...state.customer[1], address: value }
]
};
These two case statements seem to be causing an error with one another when I call the drop down function on either or, resulting in the aforementioned error. I don't see the connection. Any further input would be appreciated.
If I understand your question you miss this line:
case "SET_CUST1_PHONE_HOME_EVENING":
return {
...state,
customer: [
state.customer[0],
{
...state.customer[1],
phone: [
{
...state.customer[1].phone[0],
home: {
...state.customer[1].phone[0].home,
evening: value
}
}
]
}
]
};
I mean that you forgot to insert the customer[0] again to the state.
if this was not helpful- you can try to console.log the state before and after ans see which changes you don't want - and which code needs to be fixed according to that.
edit:
you can use something like this:
const stateCustomers = state.customer.slice();
let customer = stateCustomers.find(c => <your condition to find the desired customer>);
customer.phone[0].home.evening = value;
return {
...state,
customer: stateCustomers
};
Update:
Incase anyone is having a similar problem and having a hard time working with nested items, I would like to suggest first reading up on state immutability as recommended to me in my reddit thread on this topic.
I also found (via recommendation) a super way to deal with this type of nested state via something called immer. It's as easy as making an import statement and then wrapping your case statement in a 'produce' function, which makes a draft of your state that you can directly reference instead of spreading out all layers to make a change. So, instead of having something like this:
case "SET_CUST1_PHONE_HOME_EVENING":
return {
...state,
customer: [
state.customer[0],
{
...state.customer[1],
phone: [
{
...state.customer[1].phone[0],
home: {
...state.customer[1].phone[0].home,
evening: value
}
}
]
}
]
};
You can instead have something like this, which IMO is much cleaner and easier to read/write:
import { produce } from 'immer';
...
case "SET_CUST1_PHONE_HOME_EVENING":
return produce(state, draft => {
draft.customer[1].phone[0].home.evening = value
});
And boom! You're done.

Create keyed Maps from nested Lists with Immutable.js

I am working with a dataset that cannot be modified on the server side. So I am trying to setup the local data model on the client in a way that I can easily traverse through the model when updating parts of the data.
Therefore I am trying to create a multi-leveled Map from multi-leveled Maps including Lists, that themselves include Maps, etc. (see schematics at the end of this post).
What I am trying to get is a Map containing other Maps, with the key of the included Map being the value of the object (again please see schematics at the end of this post).
I got it to work on the first level:
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
See it in action here: https://jsfiddle.net/9f0djcb0/4/
But there is a maximum of 3 levels of nested data and I can't get my head around how to get the transformation done. Any help appreciated!
The schematic datasets:
// This is what I got
const dataset = [
{
field: 'lorem',
value: 'ipsum',
more: [
{
field: 'lorem_lvl1',
value: 'ispum_lvl1',
more: [
{
field: 'lorem_lvl2',
value: 'ispum_lvl2',
more: [
{
field: 'lorem_lvl3',
value: 'ispum_lvl3',
}
]
}
]
}
]
},
{
field: 'glorem',
value: 'blipsum'
},
{
field: 'halorem',
value: 'halipsum'
}
];
This is where I want to go:
// This is what I want
const dataset_wanted = {
ipsum: {
field: 'lorem',
value: 'ipsum',
more: {
lorem_lvl1: {
field: 'lorem_lvl1',
value: 'ispum_lvl1',
more: {
lorem_lvl2: {
field: 'lorem_lvl2',
value: 'ispum_lvl2',
more: {
lorem_lvl3: {
field: 'lorem_lvl3',
value: 'ispum_lvl3',
}
}
}
}
}
}
},
glorem: {
field: 'glorem',
value: 'blipsum'
},
halorem: {
field: 'halorem',
value: 'halipsum'
}
};
Retrieve nested structures using "getIn" is beter.
const data = Immutable.fromJS(dataset[0]);
const firstLevel = data.getIn(['more']);
const twoLevel = firstLevel.getIn([0,'more']);
const threeLevel = twoLevel.getIn([0,'more']);
console.log(firstLevel.toJS(),twoLevel.toJS(),threeLevel.toJS());
As for a more generative solution, I re-wrote the answer before to a recursive approach:
function mapDeep(firstLevel) {
return firstLevel.map((obj) => {
if (obj.has('more')) {
const sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));
const objNext = mapDeep(sec);
obj = obj.set('more', objNext);
}
return obj;
});
}
The first level still needs to be mapped manually before.
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
const secondLevel = mapDeep(firstLevel);
Again, see it in action: https://jsfiddle.net/9f0djcb0/12/
This is good enough for me for now. Still feels like this can be solved smarter (and more performant).. Cheers :)
So after some time passed I came up with a solution that works for me:
let sec, third, objThird;
// 1st level: simple mapping
const firstLevel = data.toMap().mapKeys((key, value) => value.get('value'));
// 2nd level: walk through updated firstLevel's subobjects and do the mapping again:
const secondLevel = firstLevel.map((obj) => {
if (obj.has('more')) {
sec = obj.get('more').toMap().mapKeys((key, value) => value.get('value'));
// 3nd level: walk through updated secondLevel's subobjects and do the mapping again:
objThird = sec.map((o) => {
if (o.has('more')) {
third = o.get('more').toMap().mapKeys((key, value) => value.get('value'));
o = o.set('more', third);
}
return o;
});
obj = obj.set('more', objThird);
}
return obj;
});
See it in action here: https://jsfiddle.net/9f0djcb0/7/
This has been working nicely so far, thur pretty hard-coded. If anyone has a more elegant solution to this, I am happy to learn about it!

BookShelf orm MySQL how to select column1-column2 as alias

In a raw MySQL query, I have something like this:
Select total_sales - over_head_costs As net_sales from departments;
How can I realize the same thing with BookShelf /knex query? Ideally not using knex.raw.
My attempt involves following:
let Department = bookshelf.Model.extend({
tableName: 'departments',
idAttribute: 'department_id',
},{
getDepartments: function(){
return this.fetchAll({columns: ['department_id', 'department_name', 'over_head_costs', 'total_sales - over_head_costs AS net_sales']})
.then(models=>models.toJSON());
},
});
Bookshelf does not have this feature but it brings a plugin for that: Virtuals
. No need to install anything, you just load it right after loading Bookshelf using bookshelf.plugin('virtuals').
Your model should then look like:
const Department = bookshelf.Model.extend({
tableName: 'departments',
idAttribute: 'department_id',
virtuals: {
net_sales: function() {
return this.get('total_sales') - this.get('over_head_costs');
}
}
},{
getDepartments: function(){
return this.fetchAll({columns: ['department_id', 'department_name', 'over_head_costs', 'net_sales']})
.then(models=>models.toJSON());
},
});