Optional parameters on sequelize query - node.js

Good morning.
I'm quite new to NodeJS / sequelize world and I'm currently facing a problem while trying to display a dashboard on screen.
This dashboard has three filters: two dates (period), client name, and employee name. The user can select none, one, two, or all the filters and my database needs to work accordingly.
That being said, my problem is with Sequelize because I don't know how to treat this problem of parameters not being "always" there.
I've seen this question:
Sequelize optional where clause parameters?
but this answer doesn't work anymore. I also tried another way of building the where clause, but I failed on it as well (mainly due to sequelize operators).
The last thing I tried was to make a single query with all parameters included but try to find some value (or flag) that would make sequelize ignore the parameter, for the case when the parameter was no there*, but it looks like Sequelize doesn't have anything like that.
* I've read a question here that has an answer saying that {} would do the trick but I tried that as well but didn't work.
In summary: I need to make a query that can "change" over time, for example:
Foo.findAll({
where: {
id : 1,
}
});
Foo.findAll({
where: {
id {
[Op.in] : [1,2,3,4,5]
},
name: "palmeiira",
}
});
Do you know a way of doing it without the need of using a lot if / switch statements?
I'm currently using Sequelize v. 5.5.1.
Update
I tried doing as suggested by #Anatoly and created a function to build the parameters. It was something like that. (I tried a "smaller" version just to test)
async function test() {
const where = {};
where[Op.and] = [];
where[Op.eq].push({
id: {
[Op.in]: [1,2,3]
}
});
return where;
}
I setted the return value to a const:
const query = await test()
And tried console.log(query)
The result was: { [Symbol(and)]: [ { id: [Object] } ] }, which made me believe that the problem was parsing the Op part so i tried using 'Op.and' and 'Op.in' to avoid that and it solved this problem, but led to another on sequelize that said Invalid value
Do you have any idea where is my error ?
P.S.: #Anatoly very nice idea you gave me on original answer. Thank you very much.

If these three conditions should work together then you can use Op.and with an array of conditions:
const where = {}
if (datesFilter || clientNameFilter || employeenameFilter) {
where[Op.and] = []
if (datesFilter) {
where[Op.and].push({
dateField: {
[Op.between]: [datesFilter.start, datesFilter.finish]
}
})
}
if (clientNameFilter) {
where[Op.and].push({
name: {
[Op.iLike]: `%${clientNameFilter.value}%`
}
})
}
if (employeenameFilter) {
where[Op.and].push({
employeeName: {
[Op.iLike]: `%${employeenameFilter.value}%`
}
})
}
}
const dashboardItems = await DashboardItem.findAll({ where }, {
// some options here
})
If the conditions should work as alternatives then just replace Op.and with Op.or

Related

NodeJS How to make a get request with two parameteres in the query

i'm writing a get methode in node js and i have an error when i want get the data base it show me an error that the query return null despite the document exist
router.get('/getmodele',(req,res,next)=>{
let aa=req.query.imei;
console.log(aa);
Post.findOne( {imei: {
'imei.name':req.query.imei,'imei.modele':req.query.modele
},
test: {
$exists: false
}})
.
then((posts) => {
my request take at time two parameteres
i need some helps and thank you
Use dot notation when querying.
Post.findOne( {'imei.name':req.query.imei,'imei.modele':req.query.modele})
I think your query should be like this:
{
imei: {
name: req.query.imei,
modele: req.query.modele
}
}

Prisma orderBy in a resolver/query outside of Playground

Okay, so I've been working with Prisma for a couple weeks now, and have made some great progress and I love the setup/ease of use of getting a lot of advanced features implemented.
I'm at the point I'm trying to implement sorting on table fields.
I have the options to (among other fields) sort by term_ASC and term_DESC.
Assume the following query definition: MyConnection(filter: String, order: MyOrderByInput, limit: Int, offset: Int): MyConnection!
If I run the following code in the GraphQL Playground, it works fine:
query myPaginatedResults {
myConnection(filter: "lorem", limit: 25, offset: 0, order: term_ASC) {
aggregate {
count
}
edges {
node {
id
term
}
}
}
}
Main point/question...
The usage of term_ASC/DESC works in playground, but how do I pass that in my JS?
If I wrap it in quotes "term_ASC", errors ensue, and if it's not wrapped, then it (resolver/api) throw errors about an obviously undefined variable.
const myConnection = (parent, args, context, info) => {
const where = args.filter
? {
OR: [
{ term_contains: args.filter },
{ type_contains: args.filter },
{ id_in: args.filter },
],
} : {}
const order = args.order;
// const order = `title_ASC`;
const skip = args.offset ? args.offset : 0;
const limit = args.limit ? args.limit : 50;
// console.log(context.db.query);
const results = context.db.query.myDbConnection({
where,
orderBy: order,
first: limit,
skip: skip,
}, info);
return results;
}
So the portion where I'm trying to test how to pass this orderBy variable in through a variable (hard coded, commented out in this sample) or before passing into the resolver via my args.order, I can't figure out how that should be passed.
Okay, so per usual, once my question was written down/voiced, I came up with the answer.
The problem was not that I wasn't able to wrap the enum values from MyOrderByInput in quotes in the resolver or assign to a variable pre Query, the problem was that I was trying to test with title_ASC/title_DESC which didn't exist on my Type.
-1 for me.
Lesson here: Ensure you are using an ordering method that actually DOES exist on your Prisma schema.

How to define a sort function in Mongoose

I'm developing a small NodeJS web app using Mongoose to access my MongoDB database. A simplified schema of my collection is given below:
var MySchema = mongoose.Schema({
content: { type: String },
location: {
lat: { type: Number },
lng: { type: Number },
},
modifierValue: { type: Number }
});
Unfortunately, I'm not able to sort the retrieved data from the server the way it is more convenient for me. I wish to sort my results according to their distance from a given position (location) but taking into account a modifier function with a modifierValue that is also considered as an input.
What I intend to do is written below. However, this sort of sort functionality seems to not exist.
MySchema.find({})
.sort( modifierFunction(location,this.location,this.modifierValue) )
.limit(20) // I only want the 20 "closest" documents
.exec(callback)
The mondifierFunction returns a Double.
So far, I've studied the possibility of using mongoose's $near function, but this doesn't seem to sort, not allow for a modifier function.
Since I'm fairly new to node.js and mongoose, I may be taking a completely wrong approach to my problem, so I'm open to complete redesigns of my programming logic.
Thank you in advance,
You might have found an answer to this already given the question date, but I'll answer anyway.
For more advanced sorting algorithms you can do the sorting in the exec callback. For example
MySchema.find({})
.limit(20)
.exec(function(err, instances) {
let sorted = mySort(instances); // Sorting here
// Boilerplate output that has nothing to do with the sorting.
let response = { };
if (err) {
response = handleError(err);
} else {
response.status = HttpStatus.OK;
response.message = sorted;
}
res.status(response.status).json(response.message);
})
mySort() has the found array from the query execution as input and the sorted array as output. It could for instance be something like this
function mySort (array) {
array.sort(function (a, b) {
let distanceA = Math.sqrt(a.location.lat**2 + a.location.lng**2);
let distanceB = Math.sqrt(b.location.lat**2 + b.location.lng**2);
if (distanceA < distanceB) {
return -1;
} else if (distanceA > distanceB) {
return 1;
} else {
return 0;
}
})
return array;
}
This sorting algorithm is just an illustration of how sorting could be done. You would of course have to write the proper algorithm yourself. Remember that the result of the query is an array that you can manipulate as you want. array.sort() is your friend. You can information about it here.

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,
});
}
});

Mongojs attempting to push to array

I'm trying to keep a list of all the sites I'm working on right now, and I'm having issues using $push.
I've created a document with this:
accountData = {
'accountid': account_id,
sites: {
'001': 'example.com',
}
};
db.accounts.insert(accountData);
This works great, I get:
{ accountid: 'AC654164545', 'sites.001': { '$exists': true } }
And I would like to add to the sites object. This is what I'm trying:
db.accounts.update(
{'accountid': account_id},
{
$push:
{
sites:
{
'002': 'example2.com'
}
}
},
function(err,doc){
console.log(err);
}
);
The error that I get is:
err: 'The field \'sites\' must be an array but is of type Object in document
I don't want the document to be created with an array, as I know that if I did something like this when inserting:
sites: {
'002': 'example2.com',
'003': 'example3.com',
'004': 'example4.com',
}
It would work just fine.
How do I use $push, or any other command, to add to the "sites" object without it being an array?
It can't be an array because I'm using the following to search for existing sites.
search['sites.' + site_id] = { $exists : true };
Ok, I figured out what the problem was.
I wasn't thinking about the problem in the right context.
The error was correct in saying it needed to be an array, so I changed the "sites" object into an array like this when created (initial insert), so it's an array:
accountData = {
'accountid': account_id,
sites: [{'001': 'example.com'}]
};
Then, by using the exact same code above to $push, it worked properly.

Resources