Using mssql and node-sql to UPDATE - mysql

I'm using mssql together with node-sql to build SELECT queries but I can't find any example how to use it to build UPDATE queries. I have an object where properties corresponds to table fields and I would like to update all of them.
Assume:
child: sql.define({
name: 'children',
columns: ['id', 'name', 'surname', 'group']
})
and:
var data = {/*new child data*/};
var query = child.update(data).where(child.id.equals(data.id)).toQuery().text;
How can I use this with mssql without knowing values and count of data properties?
Right now I have this:
connection.query(query, [data.id, data.name, data.surname, data.group], function(err, result) {
res.redirect('/index');
});
that can be achieved by using lodash's values:
_.values(data);
which returns array of object properties but it does not guarantee correct order which is deal breaker.
How can I tackle that problem?

This will return an array of values based on the order of table columns:
child.columns.map(function(col){return data[col.name]})
It might be possible to compact the above in shorter form with lodash.

Few days later I figured node-sql's query object also has .values property besides .text property so above update can be written as
var data = {/*new child data*/};
var query = child.update(data).where(child.id.equals(data.id)).toQuery();
connection.query(query.text, query.values, function(err, result) {
res.redirect('/index');
});

Related

Sequelize raw queries TextRow and getting data out of it

Given this query here,
let output = [];
const sql = `select * from coredb.account LIMIT ${offset},${limit}`;
let data = await sequelize.query(sql, null, {raw: true, type: sequelize.QueryTypes.SELECT});
data.forEach((item) => {
console.log(item['id'], item.id); // <-- output says "undefined, undefined"
});
the data variable is indeed hydrated with the right row data when using console.log to inspect it.
But, when I try to access the individual properties, they only ever come back as undefined. This TextRow object that Sequelize seems to return the result in doesn't seem to want to let me access then explicit rows.
Just curious what i'm missing here, am I missing an option?
I agree, Sequalize raw queries are not intuitive. You don't need the null or raw: true flag. Something like this should work:
let data = await sequelize.query(sql, {type: sequelize.QueryTypes.SELECT});
When I tried this, "data" was an array of two objects, each being the query result. So, the properties can be accessed by using index [0].... e.g.
data[0].forEach((item) => {
console.log(item['id'], item.id); // <-- output says "undefined, undefined"
});
Not yet sure WHY this occurs!
EDIT - it's because .query() should have only two arguments. Changing the call to: sequelize.query(sql, {raw: true, type: sequelize.QueryTypes.SELECT}) resulted in data being a single array (as expected).
Finally I was able to find the solution for it.
You just need to make a new array and push data into it by finding bases on key name like this:
suppose we have data in students object:
let finalArray = new Array();
for (var k in students ) {
finalArray.push(students[k])
}
console.log(finalArray) // Normal JSON array object :)
m.sequelize.query(sql, {
model,
mapToModel: true
})
.then(model => res.status(200).send(model))
.catch(error => res.status(400).send(error.toString())
})

Sequelize Query Group by day objects found by parent property

So, I'm using sequelize with a mysql instance and I have this hierarchy : a task has n images and also n metadata key value pairs.
I want to get all images based on userId column of task, and afterwards get them grouped by 'createdAt' column taking into consideration the day, since a normal groupby will be pointless ( no objects share the same datetime ). I did lots of test to try to group, and I ended up using this query, which gives bad results ( I have like 11 images for a task, and it retrieves 4 ). Honestly, i don't know what I'm doing wrong. Any of you have any idea?
This is the code snippet:
var userId = security.utils.getKeycloakSubject(req);
var where = {
userId: userId
};
db.image.findAll({
include: [{
model: db.task,
include: [{
model: db.metadata,
as: 'metadata'
}],
where: where
}],
group: [db.Sequelize.fn('DAY', db.Sequelize.col('image.createdAt'))]
}).then(function (images) {
return res.json(images);
}, function (error) {
return res.status(500).json(error);
})
I saw your question and also found this: Sequelize grouping by date, disregarding hours/minutes/seconds
It is a question about group the DAY(createdAt), looks similar with yours.
And my solution of GROUP BY DAY() is look like:
item.findAll({
attributes:
[[sequelize.fn('DATE_FORMAT', sequelize.col('TimeStamp'), '%H'), 'dates']],
group: [sequelize.fn('DAY', sequelize.col('TimeStamp'))]
}).
then(function(result){console.log(result)
}).
catch(function(error){}).catch(function(error) {
console.log(error);
});
So the raw SQL likes: SELECT DATE_FORMAT('TimeStamp', '%H') as 'dates' FROM tableName GROUP BY DAY('TimeStamp');
Hope it helps you, or you can show us the SQL you want to use, maybe it is easier to help you too.
Good luck.

Specifying specific fields with Sequelize (NodeJS) instead of *

Alright so I have a project in NodeJS where I'm utilizing Sequelize for a MySQL ORM. The thing works fantastically however I'm trying to figure out if there is a way to specify what fields are being returned on a query basis or if there's even a way just to do a .query() somewhere.
For example in our user database there can be ridiculous amounts of records and columns. In this case I need to return three columns only so it would be faster to get just those columns. However, Sequelize just queries the table for everything "*" to fulfill the full object model as much as possible. This is the functionality I'd like to bypass in this particular area of the application.
You have to specify the attributes as a property in the object that you pass to findAll():
Project.findAll({attributes: ['name', 'age']}).on('success', function (projects) {
console.log(projects);
});
How I found this:
The query is first called here: https://github.com/sdepold/sequelize/blob/master/lib/model-definition.js#L131
Then gets constructed here: https://github.com/sdepold/sequelize/blob/master/lib/connectors/mysql/query-generator.js#L56-59
Try this in new version
template.findAll({
where: {
user_id: req.params.user_id
},
attributes: ['id', 'template_name'],
}).then(function (list) {
res.status(200).json(list);
})
Use the arrays in the attribute key. You can do nested arrays for aliases.
Project.findAll({
attributes: ['id', ['name', 'project_name']],
where: {id: req.params.id}
})
.then(function(projects) {
res.json(projects);
})
Will yield:
SELECT id, name AS project_name FROM projects WHERE id = ...;
All Answers are correct but we can also use include and exclude as well
Model.findAll({
attributes: { include: ['id'] }
});
Model.findAll({
attributes: { exclude: ['createdAt'] }
});
Source

LINQ to SQL select all fields in a table but with a distinct column

I need to return a list of counties, but I need to filter out duplicate phone code values. For some reason I'm having trouble with the syntax. Can anyone show me how to do this? Should I be using the group by instead?
Group by would work if you need the actual entity.
var query = db.Counties.GroupBy( c => new { c.CountyName, c.PhoneCode } )
.Select( g => g.FirstOrDefault() );
Or if you are constructing it for a view model and only need the data, you could use Distinct. The following creates an anonymous type that could be used to populate the model.
var query = db.Counties.Select( c => new { c.CountyName, c.PhoneCode } )
.Distinct();

IQueryable Parent-Child

I need to cast: IQueryable<PARENT> to IQueryable<Child>.
IQueryable<PARENT> query = GetParents();
IQueryable<CHILD> result = query.Select(t => t.Children);
This doesn't work, unable to convert EntitySet to IQueryable. Thanks
Use:
IQueryable<CHILD> result = query.SelectMany(t => t.Children);
The query returns all cild items of the parent, childs referenced by multiple parents will be returned multiple times.
To get the distinct rows use - you will have to implement a class that Implements IComparer though, to do a custom filtering. Distinct() will look at the instances and not the values.
IQueryable<CHILD> result = query.SelectMany(t => t.Children)
.Distict(new Comparer<CHILD>());
Distinct() removes duplicats from the query.
Aternatively you can use grouping to create a grouping for the children:
IEnumerable<CHILD> result = query.SelectMany(t => t.Children)
.GroupBy(x => new CHILD {
id = x.id
// add other properties here
})
.Select(g => g.Key);
Instead of new CHILD { } you could also use new { } to create an anonymous result, in this case you should replace IEnumerable<CHILD> with var.
To perform a type cast in Linq you can use - although I would assume that this will not work in you case:
someQuery.OfType<TypeToCastTo>().Cast<TypeToCastTo>();
OfType<T>() filters the items so that Cast<T>() can perform the type cast.