sequelize find and update a record without a model - mysql

I would like to update a database record using sequelize.js and mysql2
I do not have access to the models folder or either they have not been made so is there a way to update can't find solution all solutions are that i checked are with model name dot update
var Book = db.define(‘books’, {
title: {
type: Sequelize.STRING
},
pages: {
type: Sequelize.INTEGER
}
})
Book.update(
{title: req.body.title},
{returning: true, where: {id: req.params.bookId} }
)
.then(function([ rowsUpdate, [updatedBook] ]) {
res.json(updatedBook)
})
.catch(e => console.log(e));
I would like your expert solution on that please

For latest documentation based on version refer to Sequelize ORM.
Update - v6
You can use both query model(preferred) as well as raw queries to achieve this.
// Using query model(User)
await User.update({ y: 42 }, {
where: {
x: 12
}
});
// Using raw query
const [results, metadata] = await sequelize.query("UPDATE users SET y = 42 WHERE x = 12");
// Results will be an empty array and metadata will contain the number of affected rows.
Old - v3
sequelize.query("UPDATE users SET y = 42 WHERE x = 12").spread(function(results, metadata) {
// Results will be an empty array and metadata will contain the number of affected rows.
})
Reference: Sequelize Raw Query

Related

How to verify typeorm update by createQueryBuilder() NESTJS MySql typeORM

im using NEST JS and typeorm on MySql database. Update code:
const doneReport = await createQueryBuilder()
.update(ReportAd)
.set({ status: reportStatus.done })
.where('id = :id', { id: idReport })
.execute()
.then(result => {
console.log('RESULT', result);
return result;
});
When i update data using createQueryBuilder() and putted data is valid (id) i always get back result like:
RESULT UpdateResult { generatedMaps: [], raw: [], affected: 1 }
So, i cant recoginize if this record has been changed, or in this example 'status' hasn't changed. Only one option load object from db and compare objects before and after?
if I want throw invalid id error always ill always get back somethink like this?
RESULT UpdateResult { generatedMaps: [], raw: [], affected: 0 }

Sequelize with MYSQL: Raw query returns a "duplicate" result

I have this method that performs a raw query:
Friendship.getFriends= async (userId)=>{
const result = await sequelize.query(`select id,email from users where
users.id in(SELECT friendId FROM friendships where friendships.userId =
${userId})`);
return result;
};
The result seems to contain the same exact data, but twice:
[ [ TextRow { id: 6, email: 'example3#gmail.com' },
TextRow { id: 1, email: 'yoyo#gmail.com' } ],
[ TextRow { id: 6, email: 'example3#gmail.com' },
TextRow { id: 1, email: 'yoyo#gmail.com' } ] ]
Only two records should actually be found by this query(id's 1 and 6), yet it returns an array with the same records twice.
Can somebody explain me what's going on here?
Edit: the models:
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: { type: DataTypes.STRING, unique: true },
password: DataTypes.STRING,
isActive:{type:DataTypes.BOOLEAN,defaultValue:true}
});
module.exports = (sequelize, DataTypes) => {
const Friendship = sequelize.define('Friendship', {
userId: DataTypes.INTEGER,
friendId: DataTypes.INTEGER,
});
Try to set query type to SELECT in the second argument.
sequelize.query(queryString, {type: sequelize.QueryTypes.SELECT})
I am not sure but try below code.
const result = await sequelize.query("select id,email from users where
users.id in(SELECT friendId FROM friendships where friendships.userId =
${userId})", {type: sequelize.QueryTypes.SELECT});
One more thing : Use join instead of in
TL;DR;
Use a query type to avoid duplicates being returned when the database is either MySQL or MSSQL
sequelize.query(yourQuery, {type: QueryTypes.SELECT})
Explanation
I'm answering this question because the two answers available up to this day do not explain why this happens.
As per the documentation of Sequelize:
By default the function will return two arguments - a results array, and an object containing metadata (such as amount of affected rows, etc). Note that since this is a raw query, the metadata are dialect specific. Some dialects return the metadata "within" the results object (as properties on an array). However, two arguments will always be returned, but for MSSQL and MySQL it will be two references to the same object.
To avoid this behaviour you may tell Sequelize how to format the results using a query type as shown above.

What is the idiomatic, performant way to resolve related objects?

How do you write query resolvers in GraphQL that perform well against a relational database?
Using the example schema from this tutorial, let's say I have a simple database with users and stories. Users can author multiple stories but stories only have one user as their author (for simplicity).
When querying for a user, one might also want to get a list of all stories authored by that user. One possible definition a GraphQL query to handle that (stolen from the above linked tutorial):
const Query = new GraphQLObjectType({
name: 'Query',
fields: () => ({
user: {
type: User,
args: {
id: {
type: new GraphQLNonNull(GraphQLID)
}
},
resolve(parent, {id}, {db}) {
return db.get(`
SELECT * FROM User WHERE id = $id
`, {$id: id});
}
},
})
});
const User = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: {
type: GraphQLID
},
name: {
type: GraphQLString
},
stories: {
type: new GraphQLList(Story),
resolve(parent, args, {db}) {
return db.all(`
SELECT * FROM Story WHERE author = $user
`, {$user: parent.id});
}
}
})
});
This will work as expected; if I query a specific user, I'll be able to get that user's stories as well if needed. However, this does not perform ideally. It requires two trips to the database, when a single query with a JOIN would have sufficed. The problem is amplified if I query multiple users -- every additional user will result in an additional database query. The problem gets worse exponentially the deeper I traverse my object relationships.
Has this problem been solved? Is there a way to write a query resolver that won't result in inefficient SQL queries being generated?
There are two approaches to this kind of problem.
One approach, that is used by Facebook, is to enqueue requests happening in one tick and combine them together before sending. This way instead of doing a request for each user, you can do one request to retrieve information about several users. Dan Schafer wrote a good comment explaining this approach. Facebook released Dataloader, which is an example implementation of this technique.
// Pass this to graphql-js context
const storyLoader = new DataLoader((authorIds) => {
return db.all(
`SELECT * FROM Story WHERE author IN (${authorIds.join(',')})`
).then((rows) => {
// Order rows so they match orde of authorIds
const result = {};
for (const row of rows) {
const existing = result[row.author] || [];
existing.push(row);
result[row.author] = existing;
}
const array = [];
for (const author of authorIds) {
array.push(result[author] || []);
}
return array;
});
});
// Then use dataloader in your type
const User = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: {
type: GraphQLID
},
name: {
type: GraphQLString
},
stories: {
type: new GraphQLList(Story),
resolve(parent, args, {rootValue: {storyLoader}}) {
return storyLoader.load(parent.id);
}
}
})
});
While this doesn't resolve to efficient SQL, it still might be good enough for many use cases and will make stuff run faster. It's also a good approach for non-relational databases that don't allow JOINs.
Another approach is to use the information about requested fields in the resolve function to use JOIN when it is relevant. Resolve context has fieldASTs field which has parsed AST of the currently resolved query part. By looking through the children of that AST (selectionSet), we can predict whether we need a join. A very simplified and clunky example:
const User = new GraphQLObjectType({
name: 'User',
fields: () => ({
id: {
type: GraphQLID
},
name: {
type: GraphQLString
},
stories: {
type: new GraphQLList(Story),
resolve(parent, args, {rootValue: {storyLoader}}) {
// if stories were pre-fetched use that
if (parent.stories) {
return parent.stories;
} else {
// otherwise request them normally
return db.all(`
SELECT * FROM Story WHERE author = $user
`, {$user: parent.id});
}
}
}
})
});
const Query = new GraphQLObjectType({
name: 'Query',
fields: () => ({
user: {
type: User,
args: {
id: {
type: new GraphQLNonNull(GraphQLID)
}
},
resolve(parent, {id}, {rootValue: {db}, fieldASTs}) {
// find names of all child fields
const childFields = fieldASTs[0].selectionSet.selections.map(
(set) => set.name.value
);
if (childFields.includes('stories')) {
// use join to optimize
return db.all(`
SELECT * FROM User INNER JOIN Story ON User.id = Story.author WHERE User.id = $id
`, {$id: id}).then((rows) => {
if (rows.length > 0) {
return {
id: rows[0].author,
name: rows[0].name,
stories: rows
};
} else {
return db.get(`
SELECT * FROM User WHERE id = $id
`, {$id: id}
);
}
});
} else {
return db.get(`
SELECT * FROM User WHERE id = $id
`, {$id: id}
);
}
}
},
})
});
Note that this could have problem with, eg, fragments. However one can handle them too, it's just a matter of inspecting the selection set in more detail.
There is currently a PR in graphql-js repository, which will allow writing more complex logic for query optimization, by providing a 'resolve plan' in the context.

Find row by UUID stored as binary in SequelizeJS

I have a Sequelize object called Org which represents a row in the organisations table stored in MySQL. This table has a UUID primary key(id) stored as a 16 byte varbinary. If I have the UUID of an object (bfaf1440-3086-11e3-b965-22000af9141e) as a string in my JavaScript code, what is the right way to pass it as a parameter in the where clause in Sequelize?
Following are the options I've tried
Model: (for an existing MySQL table)
var uuid = require('node-uuid');
module.exports = function(sequelize, Sequelize) {
return sequelize.define('Org', {
id: {
type: Sequelize.BLOB, //changing this to Sequelize.UUID does not make any difference
primaryKey: true,
get: function() {
if (this.getDataValue('id')) {
return uuid.unparse(this.getDataValue('id'));
}
}
},
name: Sequelize.STRING,
}, {
tableName: 'organisation',
timestamps: false,
}
});
};
Option 1: Pass UUID as byte buffer using node-uuid
Org.find({
where: {
id: uuid.parse(orgId)
}
}).then(function(org) {
success(org);
}).catch(function(err) {
next(err);
});
Executing (default): SELECT `id`, `name` FROM `Organisation` AS `Org`
WHERE `Org`.`id` IN (191,175,20,64,48,134,17,227,185,101,34,0,10,249,20,30);
Sequelize treats the byte buffer as multiple values and so I get multiple matches and the top most record (not the one that has the right UUID) gets returned.
Option 2: Write a raw SQL query and pass the UUID as a HEX value
sequelize.query('SELECT * from organisation where id = x:id', Org, {plain: true}, {
id: orgId.replace(/-/g, '')
}).then(function(org) {
success(org);
}).catch(function(err) {
next(err);
});
Executing (default): SELECT * from organisation
where id = x'bfaf1440308611e3b96522000af9141e'
I get the correct record, but this approach is not really useful as I have more complex relationships in the DB and writing too many queries by hand beats the purpose of the ORM.
I'm using Sequelize 2.0.0-rc3.
Solved it by supplying a fixed size empty Buffer object to uuid.parse().
Got it working initially using ByteBuffer, but then realised that the same can be achieved using uuid.parse()
Org.find({
where: {
id: uuid.parse(orgId, new Buffer(16))
}
}).then(function(org) {
console.log('Something happened');
console.log(org);
}).catch(function(err) {
console.log(err);
});
Executing (default): SELECT `id`, `name` FROM `Organisation` AS `Org`
WHERE `Org`.`id`=X'bfaf1440308611e3b96522000af9141e';
If the accepted answer didn't work for you, here's what worked for me.
Note: My objective is to find an instance of an event based on a column which is not the primary key.
// guard clause
if (!uuid.validate(uuid_code))
return
const _event = await event.findOne({ where: { uuid_secret: uuid_code } })
// yet another guard clause
if (_event === null)
return
// your code here

How to return the number of children for tree nodes in Sequelize?

I have a hierarchical tree data structure defined like this:
module.exports = function(sequelize, DataTypes) {
var Category = sequelize.define('Category', {
id: { type: DataTypes.STRING, primaryKey: true },
parent: DataTypes.STRING,
text: DataTypes.STRING
}
);
Category.belongsTo(Category, { foreignKey: 'parent' });
return Category;
};
I have a service returning the list of children for a given node like this:
exports.categoryChildren = function(req, res) {
var id = req.params.id;
db.Category.findAll({ where: { parent: id }}).success(function(categories){
return res.jsonp(categories);
}).error(function(err){
return res.render('error', { error: err, status: 500 });
});
};
Is there a way to make Sequelize to return the number of grandchildren for every child of the given node (i.e. the grandchildren of the given node)?
The SQL query I'd use for that looks like this:
SELECT *, (select count(*) from Categories chld where chld.parent = cat.id)
FROM `Categories` cat
WHERE cat.`parent`='my_node_id';
However, I can't find a way to force Sequelize to generate a query like that.
I ended up using two nested queries as shown below.
Pros: I'm staying within the ORM paradigm.
Cons: the obvious performance hit.
exports.categoryChildren = function(req, res) {
var id = req.params.id;
db.Category.findAll({ where: { parent: id }}).success(function(categories) {
var categoryIds = [];
_.each(categories, function(element, index, list) {
categoryIds[element.id] = element;
});
db.Category.findAll({attributes: [['Categories.parent', 'parent'], [Sequelize.fn('count', 'Categories.id'), 'cnt']], where: { parent: { in: _.keys(categoryIds) }}, group: ['Categories.parent']}).success(function(counts) {
_.each(counts, function(element, index, list) {
categoryIds[element.dataValues.parent].dataValues.cnt = element.dataValues.cnt;
});
return res.jsonp(categories);
}).error(function(err){
return res.render('error', {
error: err,
status: 500
});
});
}).error(function(err){
return res.render('error', {
error: err,
status: 500
});
});
};
I ran into this same issue. So far the only thing I could figure out to do was using raw queries.
There are just some things ORMs can't do, I think this might be one of those things. You can just use query()
sequelize.query('select * from all_counts').success(function(counts) {...})
Just did not use ORM to calculate that kind of stuff. It is performance disaster.
Use database queries (like SQL you specified) and define view for that SQL, and use model to work with that view.