Similar string matching in Sequelize MYSQL - javascript

I'm new to Sequelize and JS and might not know all operators so I want to ask if there's any way to retrieve an entry from a database which is similar to but not an exact match. So for example the string I'm searching for is +921234567890 but in the database its stored as +92-1234567890, separated with a hyphen for country dialing codes.
The db I'm using is MySQL.
I tried this which I know is incorrect but I'm not sure how to move ahead:
where: {
cell: {
[Op.or]: {
[Op.like]: "%-%",
[Op.eq]: cellNumber,
},
},

You can use the REGEX_REPLACE() sql function to replace any non-numeric characters in the cell column before comparing to your input. Use the sequelize.where(), sequelize.fn(), and sequelize.col() functions to generate the query. Assuming your table is model and Model is Model.
const cellNumber = 1234567890;
const results = await Model.findAll({
where: sequelize.where(
sequelize.fn('REGEXP_REPLACE', sequelize.col('model.cell'), '[a-zA-Z]+', ''),
'=',
cellNumber
),
});
This should generate SQL similar to:
SELECT * FROM `model`
WHERE REGEXP_REPLACE(`model`.`cell`, '[a-zA-Z]+', '') = 1234567890;

The solution to this issue was solved using raw sql query but for anyone looking for an answer when using REGEXP_REPLACE, you should use REPLACE with sequelize.literal:
cell: { [Op.eq]: this.sequelize.literal("REPLACE('cell','-','')") }

Related

how to use .populate() in javascript

I have a collection called
CR
what I want to do is query CR like so:
let cre = await CR.find({myid: "xxxxxx"})
and i also have a collection called cla, but that one i need to query based off of the results of cre. The results of cre will return a class_id, in which I need to use to query the cla collection to find the _id. At the end of all of this, I want to ideally merge the two, which I believe you can do through .populate(), and then send it to teh front-end as one.;
I have tried this:
let cre = await cr.find({myid: "xxx"}).populate('loc').populate('desc').populate('dt');
but this isn't working. how can I fix this?
It may be due to schemas, but this is how it's clean and simple to use;
let cre = await cr.find({myid: "xxx"}).populate(['loc','desc','dt']);
Firstly, you can take cla collection "_id" in CR collection schema. In schema of CR collection refer to cla model id like this,
const creSchema = mongoose.Schema({
name: String,
classnId: { type: mongoose.Types.ObjectId, ref: "Cla" }
});
Then you can populate like,
const cres = await CR.find({}).populate({path:'classnId', select:'columnName'});
Hopefully, this will solve your issue.
Note: There in populating you can give multiple column names by space and if you give a minus before a column name like this (-columnName) then that column will not show when you will call the API.

Sequelize how to return result as a 2D array instead of array of objects?

I am using Sequelize query() method as follows:
const sequelize = new Sequelize(...);
...
// IMPORTANT: No changed allowed on this query
const queryFromUser = "SELECT table1.colname, table2.colname FROM table1 JOIN table2 ON/*...*/";
const result = await sequelize.query(queryFromUser);
Because I am selecting two columns with identical names (colname), in the result, I am getting something like:
[{ "colname": "val1" }, { "colname": "val2" }...], and this array contains values only from the column table2.colname, as it is overwriting the table1.colname values.
I know that there is an option to use aliases in the SQL query with AS, but I don't have control over this query.
I think it would solve the issue, if there was a way to return the result as a 2D array, instead of the array of objects? Are there any ways to configure the Sequelize query that way?
Im afraid this will not be possible without changes in the library directly connecting to the database and parsing its response.
The reason is:
database returns BOTH values
then in javascript, there is mapping of received rows values to objects
This mapping would looks something like that
// RETURNED VALUE FROM DB: row1 -> fieldName:value&fieldName:value2
// and then javascript code for parsing values from database would look similar to that:
const row = {};
row.fieldName = value;
row.fieldName = value2;
return row;
As you see - unless you change the inner mechanism in the libraries, its impossible to change this (javascript object) behaviour.
UNLESS You are using mysql... If you are using mysql, you might use this https://github.com/mysqljs/mysql#joins-with-overlapping-column-names but there is one catch... Sequelize is not supporting this option, and because of that, you would be forced to maintain usage of both libraries at ones (and both connected)
Behind this line, is older answer (before ,,no change in query'' was added)
Because you use direct sql query (not build by sequelize, but written by hand) you need to alias the columns properly.
So as you saw, one the the colname would be overwritten by the other.
SELECT table1.colname, table2.colname FROM table1 JOIN table2 ON/*...*/
But if you alias then, then that collision will not occur
SELECT table1.colname as colName1, table2.colname as colName2 FROM table1 JOIN table2 ON/*...*/
and you will end up with rows like: {colName1: ..., colName2: ...}
If you use sequelize build in query builder with models - sequelize would alias everything and then return everything with names you wanted.
PS: Here is a link for some basics about aliasing in sql, as you may aliast more than just a column names https://www.w3schools.com/sql/sql_alias.asp
In my case I was using:
const newVal = await sequelize.query(query, {
replacements: [null],
type: QueryTypes.SELECT,
})
I removed type: QueryTypes.SELECT, and it worked fine for me.

Handling SQL comparison operators in express GET routes - Filtering

I'm having struggle to use SQL comparison operators in express GET routes.
I know that, with MongoDB (using Mongoose), we can GET a route like so :
app.get('/users?age[gte]=20', …)
Which we can then handle like so in our controller function :
// Get the query parameters from the GET URL :
const queryObj = { ...req.query };
let queryStr = JSON.stringify(queryObj);
// Modify the comparison operators passed in the query (add the $ sign) :
queryStr = queryStr.replace(/\b(gte|gt|lte|lt)\b/g, match => `$${match}`);
console.log(JSON.parse(queryStr)); // Returns { age: { '$gte': '20' } }
// With the above example - GET /users?age[gte]=20 -, we can then use it directly to fetch users with age >= 20 :
const users = await Users.find(JSON.parse(queryStr));
However, how can I do this for SQL comparison operators, using Knex ? As we don't want them to be nested in the query string object.
I tried different REGEX to get >=, >, <, <=, instead of the Mongoose ones ($gte, $gt,…), the problem is that, with the brackets in the query string, I get something like this :
queryStr = queryStr.replace(/\bgte\b/g, '>=');
console.log(JSON.parse(queryStr)); // Returns { age: { '>=': '20' } }
Because I use Knex, as far as I know, I can not directly use this kind of object in the query, as I did with Mongoose.
What is the best way to deal with this and "automate" the filtering function like I did with the Mongoose example ?
Thank you very much

Use JS object as values on mySQL query string

Im using pool to query mySQL on nodejs. We doing and it is working fine.
let values = [1, 2, 3];
DB.pool.query('SELECT * ROM table_name WHERE col1 = ? AND col2 = ? AND col3 = ?' , values, ( err, rows ) => {
//Do something
});
As you can notice, the where values are on array and we use ? on the query string to insert those values. The problem with this is, on complex queries, there are alot of value.
Is there a way to use object instead?
Something like:
let values = {col1: 1, col1: 2, col1: 3};
and the query string would be like:
SELECT * ROM table_name WHERE col1 = :col1 AND col2 = :col2 AND col3 = :col3
Any help would be appreciated.
You might be looking for a query builder like knex or slonik.
You could write your own utility function to help interpolate strings into queries, maybe using the JS Template Literals, but there are packages like the above which already exist to help you do some of this.
Ultimately, the answer is "not really". A SQL query is essentially a string. Either you are going to work with a client/library that builds a query for you (which is what whatever client you're already using is doing, letting you pass in an array of values to get interpolated into the string), or you are going to manually create your strings yourself somehow.

Firestore create compound query from array

I'm trying to create a compound query to do a range query.
let query;
category.queryParams.query.fieldFilters.forEach(function(fieldFilter) {
query = collection.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
});
But it's not giving me the results I want.
I'm having a feeling that the query needs to be created chained like collection.where().where()
If that is the case, how can I transform the contents of my array using that syntax?
From my understanding, you have an array named fieldFilters that contains multiple objects with a field attribute (e.g. 'price'), a filterType attribute (e.g. '>') and a filterValue attribute (e.g. 50). If you are trying to do multiple range queries on different fields, then this will not work as stated in the documentation https://firebase.google.com/docs/firestore/query-data/queries#compound_queries. Solutions do exist for this problem, I suggest you read Frank van Puffelen response to the following question: Firestore multiple range query.
Solved it with this code:
let query;
category.queryParams.query.fieldFilters.forEach(function(fieldFilter) {
if (typeof query === "undefined") {
query = collection.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
} else {
query = query.where(fieldFilter.field, filterOperationString(fieldFilter.filterType), fieldFilter.filterValue);
}
});

Categories

Resources