How to update a ManyToMany relationship in Objection JS? - objection.js

I am learning Objection JS. I have a manyToMany relationship on an accounts and roles table that are related through an accounts_roles table. I was wondering if there was a way to update account roles on the account model by doing something like:
AccountOne.addRoles([roleId])
AccountOne.removeRoles([roleId])
AccountOne.updateRoles([roleId])
AccountOne.deleteRoles([roleId])
I searched online and went through the official objection documentation. So far I can do a GraphInsert, on my account model with a role object "x", and that creates a new role "x" with a relationship correctly defined in accounts_roles. But that always creates a new role. I would like to add and remove relationships between existing accounts and roles. Any help would be much appreciated.

You can use relate and unrelate to connect two rows together in a many-to-many relationship. Obviously, for this to work, you have to have your Models' relationMappings set up correctly. I have put a pair of example models too. It's critical that you match your key of your relationMappings to what you put in your $relatedQuery method to call relate/unrelate on.
Example Models
//Person and Movie Models
const { Model } = require('objection');
class Person extends Model {
static tableName = 'persons';
static get relationMappings() {
return {
movies: {
relation: Model.ManyToManyRelation,
modelClass: Movie,
join: {
from: 'persons.id',
through: {
from: 'persons_movies.person_id',
to: 'persons_movies.movie_id'
},
to: 'movies.id'
}
}
};
}
}
class Movie extends Model {
static tableName = 'movies';
static get relationMappings() {
return {
persons: {
relation: Model.ManyToManyRelation,
modelClass: Person,
join: {
from: 'movies.id',
through: {
from: 'persons_movies.movie_id',
to: 'persons_movies.person_id'
},
to: 'persons.id'
}
}
};
}
}
Relate Example
In the case of a many-to-many relation, creates a join row to the join table.
const person = await Person
.query()
.findById(123);
const numRelatedRows = await person
.$relatedQuery('movies')
.relate(50);
// movie with ID 50 is now related to person with ID 123
// this happened by creating a new row in the linking table for Movies <--> Person
Unrelate Example
For ManyToMany relations this deletes the join row from the join table.
const person = await Person
.query()
.findById(123)
const numUnrelatedRows = await person
.$relatedQuery('movies')
.unrelate()
.where('id', 50);
// movie with ID 50 is now unrelated to person with ID 123
// this happened by delete an existing row in the linking table for Movies <--> Person

Related

How to get data sorted with relation using TypeORM?

I want to get user data with relation sorted but with this code it just sort the user but I want to sort data that have relation with user I'm using eager, could any one help me ?
getUerWithId(pramas: string): Observable<userEntity[]> {
return from(this.userRepository.find({
where: [
{ id: pramas }
],
order:{
id:'DESC'
}
}))
}
With the repository, I don't know if it is possible, but you can try with query builder to get ordered relations. Follow example bellow:
this.userRepository.createQueryBuilder()
.innerJoinAndSelect("User.notification", "Notification")
.orderBy({'Notification.createdAt': 'DESC'})
.where("User.id = :id", {
id: Number(id),
})
.getOne();
Remember to put the right relationship for your entity, and right names for your properties.

TypeORM / Postgres - Include all in relation where at least one meets requirement

I am very new to SQL/TypeORM in general and I'm currently facing a problem where I want to load match participants related to a match where at least one participant has a passed userId. The query could be thought of as "Load all my matches with my opponents". I have three tables:
public.match << OneToMany >> public.match_participant << ManyToOne >> public.user
So far I have gone about doing:
select * from public.match m
left join public.match_participant mp on mp."matchId" = m.id
left join public.user u on u.id = mp."userId"
where u.id = 3
and in typeORM
repository
.createQueryBuilder('match')
.leftJoinAndSelect('match.participants', 'participants')
.leftJoinAndSelect('participants.user', 'user')
.where('user.id=:id')
.setParameter('id', 1)
.getMany();
Which of course loads all matches, participants and users for that particular userId but other participants are not included. I believe something like a "subquery" could be of use but I can't seem to figure it out.
Any help is greatly appreciated!
Thanks in advance.
After a bunch of trial and error I learned how to convert a pure query to the builder. The solution was the following:
matchRepository
.createQueryBuilder('match')
.innerJoin(
query => {
return query
.from(MatchParticipant, 'p')
.select('p."matchId"')
.where('p."userId" = :id');
},
'selfMatch',
'"selfMatch"."matchId" = match.id',
)
.leftJoinAndSelect('match.participants', 'participants')
.leftJoinAndSelect('participants.user', 'user')
.setParameter('id', id)
.getMany();
I don't think you even need the query builder for this.
#Entity()
class Match {
#OneToMany(...)
participants: MatchParticipant[];
}
#Entity()
class MatchParticipant {
#ManyToOne(...)
match: Match;
#ManyToOne(...)
participant: Participant;
}
#Entity()
class User {
#OneToMany(...)
matches: MatchParticipant[];
}
// ...
repository.manager.find(MatchParticipant, { where: { match: { participants: { participant: { id } } } } });

How to query all the owned objects in one query MTM?

I have a list of the owning side of a many-to-many relationship. How do I query all the owned objects in one query using Grails GORM? In SQL I would used the join table and the owned table and the ids for the owning table with an in clause.
Example domain classes:
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}
class Author {
static hasMany = [books:Book]
String name
}
So I have a List or Set of Authors and I want to find all their Books in one query.
select b.*
from book b
join author_book ab on b.id = ab.book_id
where ab.author_id in (1, 2, 3);
In Grails I tried the following but it fails.
def books = Book.withCriteria {
inList('authors', authors)
}
You need to join the author first:
def books = Book.withCriteria {
authors {
inList('id', authors*.id)
}
}
Is this what you're looking for?
Book.findAllByAuthorInList(authors)

eloquent refer to a column of a related a model

I have three tables:
categories
id, title
products
id, name
categories_products
id, category_id, product_id
I have also setup the according models and relationships (both have belongsToMany of the other)
Now I want to get all products belonging to a category
Category::where('title','Electronics')->first()->products()->limit(10)->get(['products.name']);
which works fine, but I also want to include the category title for each product as well:
Category::where('title','Electronics')->first()->products()->limit(10)->get(['products.name','category.title']);
However it returns: Column not found category.title
I thought that the relation would take care of it.
EDIT: Models -->
Category:
class Category extends Model
{
protected $fillable = array('title');
public function products()
{
return $this->belongsToMany('Product', 'categories_products', 'category_id', 'product_id');
}
}
class Product extends Model
{
protected $fillable = array('name');
public function categories()
{
return $this->belongsToMany('Category', 'categories_products', 'product_id', 'category_id');
}
}
The reason you're getting the error is because get() works just like select() and because you're running the category query and then running the product query after there is no categories table to reference for the select.
Look into Eager Loading. It will help with a lot of these kinds of issues. Your query can be written as:
Product::select('id', 'name')
->with(['categories' => function($query) {
return $query->select('id', 'title');
}])
->whereHas('categories', function($query) {
return $query->where('title', 'Electronics');
})
->limit(10)
->get();
Because we are lazy loading you NEED the id column on each model so Laravel knows where to attach the relationships after the queries are run.
The with() method above will eager load the categories relationship and the whereHas() method puts a relationship constraint on the current query.
UPDATE
Similar query from Category model:
$category = Category::where('title','Electronics')
->with(['products' => function($query) {
return $query->select('id', 'name')->limit(10);
}])
->first(['id', 'title']);
Then access the products with:
$category->products

How to save Father and Child document with MongooseJS

I'm quite new in MongoDB & MongooseJS. Actually learning the MEAN stack, I already love it.
I'm not sure to exactly understand noSQL principles, sorry If I duplicate.
I want to join 2 documents, type father and child, with 1 to N relationship.
Here's two solutions:
• Sub documents: http://mongoosejs.com/docs/subdocs.html
• References: http://mongoosejs.com/docs/populate.html
I've chosen the first one, simpler and IHMO closer to my problem.
Here's the code:
var personSchema = new Schema({
name : String
});
var groupSchema = new Schema({
name : String,
persons : [ personSchema ]
});
var Group = module.exports = mongoose.model('Group', groupSchema);
var Person = module.exports = mongoose.model('Person', personSchema);
Group.findById(groupId, function(err, group) {
var person = new Person();
person.name = "john";
group.persons.push(person);
group.save();
});
When I check for all groups, it work perfectly. The groups are returned, with the people saved.
Group.find(function(err, group) {
// group is full of groups & people
}
But when I check for person, nothing is returned.
Person.find(function(err, person) {
// person is empty
}
It seems that only the Group table document was filled. Is the solution implies to save 1/ the person and 2/ the group, and if so, will Person be saved in two different places (in Group document and in Person document)?
Group.findById(groupId, function(err, group) {
var person = new Person();
person.name = "john";
group.persons.push(person);
person.save(function(...) {
group.save();
});
});
Thanks