Can't create object with relation one-to-many - node.js

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.

Related

how to attach or detach record on many to many sequelize association?

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.

MongoDB: add object to subarray if not exists

I searched many questions here and other articles on the web, but they all seem to describe somehow different cases from what I have at hand.
I have User schema:
{
username: { type: String },
lessons: [
{
lesson: { type: String },
result: { type: String }
}
]
}
I want to add new element into lessons or skip, if there is already one with same values, therefore I use addToSet:
const dbUser = await User.findOne({ username })
dbUser.lessons.addToSet({ lesson, result: JSON.stringify(result) })
await dbUser.save()
However it makes what seems to be duplicates:
// first run
[
{
_id: 60c80418f2bcfe5fb8f501c1,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
}
]
// second run
[
{
_id: 60c80418f2bcfe5fb8f501c1,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
},
{
_id: 60c80470f2bcfe5fb8f501c2,
lesson: '60c79d81cf1f57221c05fdac',
result: '{"correct":2,"total":2}'
}
]
At this point I see that it adds _id and thus treats them as different entries (while they are identical).
What is my mistake and what should I do in order to fix it? I can change lessons structure or change query - whatever is easier to implement.
You can create sub-documents avoid _id. Just add _id: false to your subdocument declaration.
const userSchema = new Schema({
username: { type: String },
lessons: [
{
_id: false,
lesson: { type: String },
result: { type: String }
}
]
});
This will prevent the creation of an _id field in your subdoc, and you can add a new element to the lesson or skip it with the addToSet operator as you did.

Updating aliases with sequalize db

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?

Sequelize and querying on complex relations

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

nodejs sequelize join query

Suppose i have two models
var A = db.seq.define('A',{
id1: { type: db.Sequelize.INTEGER},
id2: { type: db.Sequelize.INTEGER},
count: { type: db.Sequelize.INTEGER},
});
var b = db.seq.define("b",{
id1: { type: db.Sequelize.INTEGER },
id2: { type: db.Sequelize.INTEGER },
name: { type: db.Sequelize.STRING},
});
A.hasMany(B, {foreignKey: 'id1'})
B.belongsTo(A, {foreignKey: 'id1'})
A.findAll({
include: [{
model: B,
where: { B.id2: { $eq:A.id2 } }
}]
})
Its possible to make that kind of query?
How can i update my model to specify some other condition on the join sentence or should i move the check to the query where clause?
Some example will be really helpful
Thanks
Try
A.findAll({
include: [{
model: B,
where: { id2: sequelize.col('A.id2') }
}]
})
id2 will automatically reference B.
Currently Jan Aagaard Meier's answer is not fully working
I have found out that id2 is not recognized in the actual query.
For example the query
A.findAll({
include: [{
model: B,
where: { id2: sequelize.col('A.id2') }
}]
})
should recognize as inner join on 'A'.'PrimaryKey' = 'B'.'ForeignKey' and id2 = 'A'.'id2'
but somehow sequelize does not add up the left side so it ignores as
'A'.'PrimaryKey' = 'B'.'ForeignKey' and 'A'.'id2'
so query is not working
I've done the raw query that is printed when sequelize is executed and found out what was wrong.
Does anyone have an idea to solve this?
found the answer
A.findAll({
include: [{
model: B,
where: { sequelize.col('A.id2), "=", sequelize.col('B.id2') }
}]
})
This works fine for me. Hope this works well for you

Resources