In my data model, I have an instance: db.items , which has relation "hasMany" with db.images, db.services. So one item can have many images and many services.
I would like to update my instance calling the following:
let res = await db.items
.upsert(
{
id: req.body.id,
type: req.body.type,
name: req.body.name,
images: req.body.images,
services: req.body.services
},
{
include: [
{
model: db.images,
as: "images"
},
{
model: db.services,
as: "services"
}
]
}
);
The problem is that all the aliases are not updated, but the name and type of the item updated. What could be the problem? Include perfectly works with db.create() call, but with upsert - maybe there is a different way of doing things?
Related
Working on an already setup db and also new to sequelize. I have like four tables
customer
library
books
excerpt
excerpt has redundant book_id from books. books has redundant library_id from library, and library has redundant customer_id from customer.
They were not declared foreign in db but its kinda acting the foreign key type and I make the association when I hit the orm functions.
My question:
I have a customer_id and book_id, and I have to fetch excerpt records based on book_id but have to go top the db to match the customer_id as well. (for multi tenancy)
the flow is: excerpt> book_id - books > library_id - library > customer_id - customer
I have written this code but its not working
async read_book_id(customer_id, book_id) {
const excerpts = await this.model.findAll({ // this.model being the excerpt model
where: { book_id: book_id},
include: [
{
model: this.db.Books,
association:
this.model.belongsTo(this.db.Books, {
foreignKey: 'book_id',
}),
where: { book_id: book_id},
include: [
{
model: this.db.Library,
association: this.model.belongsTo(this.db.Library, {
foreignKey: 'library_id',
}),
where: { customer_id: customer_id },
},
],
},
],
});
Basically this is something extended from this another code i wrote which is working for me. If I have to check only one level above thats working fine for me e.g
// reading books based on library_id
async read(customer_id, library_id) {
const books= await this.model.findAll({
where: {
library_id: library_id,
},
include: [
{
model: this.db.Library,
association: this.model.belongsTo(this.db.Library, {
foreignKey: 'library_id',
}),
where: { customer_id: customer_id },
},
],
});
}
This works fine for me.
Can you please tell how to run the first code block?
Assuming you already registered all associations just like I suggested in the comments above you need to indicate the correct models in include options along with correct conditions:
const excerpts = await this.model.findAll({ // this.model being the excerpt model
where: { book_id: book_id},
include: [
{
model: this.db.Books,
include: [
{
model: this.db.Library,
where: { customer_id: customer_id },
required: true
},
],
},
],
});```
I have many to many association like this following model:
const Movie = sequelize.define('Movie', { name: DataTypes.STRING });
const Actor = sequelize.define('Actor', { name: DataTypes.STRING });
const ActorMovies = sequelize.define('ActorMovies', {
MovieId: {
type: DataTypes.INTEGER,
references: {
model: Movie,
key: 'id'
}
},
ActorId: {
type: DataTypes.INTEGER,
references: {
model: Actor,
key: 'id'
}
}
});
Movie.belongsToMany(Actor, { through: ActorMovies });
Actor.belongsToMany(Movie, { through: ActorMovies });
And I succsessfully create Movie when create an Actor record with this following code:
Actor.create({
name: 'Jhony',
movies: [
{ name: 'Movie 1'}, // it will generate Movie with ID 1
{ name: 'Movie 2'} // it will generate Movie with ID 2
]
}, {
include: [ Movie ]
})
but my question how can I attach multiple existing Movie record when creating an Actor?
I already try:
Actor.create({
name: 'Edward',
movieIds: [1, 2]
}, {
include: [ Movie ]
})
and:
Actor.create({
name: 'Edward',
movies: [{id: 1}, {id: 2}]
}, {
include: [ Movie ]
})
But stil didn't work. Anyone can help me, please. Thanks in advance
You can't link existing movies to a new actor while creating it. You need to call setMovies of the new actor model instance:
const actor = await Actor.create({
name: 'Edward',
})
await actor.setMovies([1, 2])
Also, please pay attention that if you execute more than one query that changes something in DB it would be much more reliable to use transactions to turn all this queries into one atomic operation.
I'm a newbie in sequelize, so got some troubles with the trivial task. I have a db definition:
items.hasMany(images, {as: 'images', foreignKey: 'itemID'});
When I'm creating an item like this ...
let result = await db.items.create(
{
type: req.body.type,
name: req.body.name,
images: [req.body.images]
},
{
include: [ {model: db.images, as: "images" } ]
}
);
... I'm getting an error:
TypeError: instance.set is not a function
What could be the problem? Or it is not a correct way of insertion?
SOLUTION
The problem was in the type of object that I pass. I was passing [req.body.images], but it was already an array. So removing [] problem solved.
Thanks to everyone who checked it :)
let result = await db.items.create([
{
type: req.body.type,
name: req.body.name,
images: [req.body.images]
},
{
include: [ {model: db.images, as: "images" } ]
}
]);
Wrap args with array in create function(). Hope it might help u.
With Sequelize, I have two models with many to many association : User and Category.
I want to get all categories that belongs to the current user, and also categories with a certain property, but I don't understand how, with only one query...
I'm using the Op.or operator, according to the documentation, and the $Model.attribute$ syntax for associated model (seen here).
let categories = await models.category.findAll({
where: {
[Op.or]: [
{ someCategoryProperty: true },
{ '$User.id$': req.currentUser.id },
],
},
include: [{
model: models.user,
as: 'User',
}],
});
The operator works if I add 2 conditions about the Category model, but how to add a condition on the association ?
I finally found the tips :
Actually, $Model.attribute$ wasn't the good pattern, $database_table_name.attribute$ is the good one.
With the '$..$' syntax, we must use the database table name, and not the model.
If my model is called user, Sequelize set the database name users !
So this code works :
let categories = await models.category.findAll({
where: {
[Op.or]: [
{ someCategoryProperty: true },
{ '$users.id$': req.currentUser.id },
],
},
include: [{
model: models.user,
}],
});
Thanks
I'm trying to understand how best to perform a query over multiple entities using Sequelize and Node.js.
I have defined a model "User" which has a belongsToMany relation with a model "Location". I then have a model "Asset" which also has a belongsToMany relation with "Location". When I have an instance of a User I would like to fetch all Assets that are associated with Locations that the User is associated with.
I tried the following which doesn't seem to work...
user.getLocations().then(function(userLocations) { return Asset.findAll({ where: { "Locations" : { $any : userLocations } }) })
Could anyone offer any suggestions?
Try this query:
User.findById(user_id, {
include: [{
model: Location,
required: true
}]
}).then(user => Asset.findAll({
where: {
user_id: user.id,
location_id: {
$in: user.locations.map(location => location.id)
}
}
})).then(assets => {
// The rest of your logic here...
});
This was the final result...
User.findById(user_id, {
include: [{
model: Location,
as: 'Locations', // Was needed since the original relation was defined with 'as'
required: true
}]
}).then(user => Asset.findAll({
include: [{
model: Location,
as: 'Locations',
where: {
id: {
$in: user.Locations.map(location => location.id)
}
}
}]
})).then(assets => {
// The rest of your logic here...
});