I'm using BookshelfJS. I have two models users and posts. Obviously, the relationship here is many to many. So I have a pivot table post_user.
Now, given a user_id, I want to find all the posts for that user. So far, I've managed to do this using knex:
knex.select()
.from('post_user')
.where('user_id', user_id)
.then(function (pivots) {
// Now loop through pivots and return all the posts
// Using pivot.post_id
pivots.map(function(pivot) {})
});
Is there a cleaner way of doing this?
You'll want to define the many-to-many relationship in your Bookshelf models. Something like this:
var User = bookshelf.Model.extend({
tableName: 'users',
posts: function() {
return this.belongsToMany(Post);
}
});
var Post = bookshelf.Model.extend({
tableName: 'posts',
users: function() {
return this.belongsToMany(User);
}
});
By convention, the pivot table Bookshelf would be using is posts_users (table names combined with _, starting from the table that is alphabetically first). It should contain a user_id and a post_id (and a coposite PK of those two). If you don't wish to rename the pivot table, see the documentation for belongsToMany for instructions on how to define the table and ids of your pivot table.
After this, you can query your model with Bookshelf:
return new User().where('id', user_id)
.fetch({withRelated: 'posts'})
.then(function (user) {
var postCollection = user.get('posts');
// do something with the posts
});
See also the documentation for fetch.
Related
I'm struggling with queries over many-to-many relation using typeorm.
I have two entities: users and groups, both having many-to-many relations to each other.
User entity has this:
#ManyToMany(() => Group, group => group.users)
#JoinTable()
groups: Group[];
Group entity has this:
#ManyToMany(() => User, user => user.groups)
users: User[];
I want to get all groups of a specified user, that have a certain value. In my case, I want all groups for user X that have ishidden = false. So I tried diffentent things, but none work...
const groups = this.groupRepository.find({
relations: ['users'],
where: {
ishidden: false,
users: {
id: user.id
}
}
});
I was really hoping that it would work this way, but it just throws Cannot query across many-to-many for property users. Other approaches with querybuilder also didnt work :-(
I can't be that hard the query a related table, can it? I'm coming from the C# world, so maybe I'm just doing it wrong ;-)
Recently faced a similar problem(nestjs + ts + typeorm). Try something like this:
import { Connection } from 'typeorm';
// some code
constructor(private connection: Connection) {}
// some code
await this.connection
.getRepository(Group) // group entity
.createQueryBuilder('groups') // table name
.leftJoin('groups.users', 'users') // join group table and user table
.where('ishidden = false AND users.id = :userId ', {
userId: userId,
})
.getMany();
I am using Sequelize for PostgresSQL. For example: I've got two tables Friendship and User. To make friendship possible for every user, I've got two relations n:n.
Associations in Sequelize
User.hasMany(Friendship,
{
as: "friendshipsAsked",
foreignKey: "asked_user_id",
joinTableName: "friendship"
});
User.hasMany(Friendship,
{
as: "friendshipsAsking",
foreignKey: "asking_user_id",
joinTableName: "friendship"
});
Friendship.belongsTo(User,
{
...
});
Friendship.belongsTo(User,
{
...
});
My biggest problem is querying friendships for user. When I've got user model, I have to get user.getFriendshipsAsking() and user.getFriendshipsAsked() and then merge both.
Is there any possibility to change relations so I can have user.getFriendships() in SQL such that it will perform like SELECT * FROM frienships WHERE requesting_user_id = 'user.id' OR requested_user_id = 'user.id'?
I would like to have a better solution to model friendship between users in the database?
I have a table in my database called users. In this table I only store user ID, username and password. Now, in another table called user_meta, I have the following columns: id, uid, meta_key, meta_value. I'm trying to find a way for Bookshelf to automatically load all records in user_meta where uid == userid, and store them as model.meta[meta_key] = meta_value. Sadly, I haven't been able to find a way to make this possible.
If it is possible at all, the 2nd step would be to also save all values in model.meta back on update / insert, inserting records where meta_key doesn't exist for that user ID yet, and updating where it does.
Try to set the associations (relations) between the models:
var User = bookshelf.Model.extend({
tableName: 'users',
meta: function() {
return this.hasMany(Meta);
}
});
var Meta = bookshelf.Model.extend({
tableName: 'user_meta',
user: function() {
return this.belongsTo(User);
}
});
http://bookshelfjs.org/#one-to-many
Im currently having an issue where i want to specify to the bookshelf model which field to use to make the data relation.
it seems to always use the id (primary key) of the model table; as far as i've found out it's only possible to set column for the relation but not which to use from model.
for example:
var StopsWithCustomer = bookshelf.Model.extend({
tableName: 'stops',
customers: function () {
return this.hasOne(customerWithStop, 'id');
}
});
it has to match on customerWithStop on the column id but it has to use the column customer_id from 'stops' to make this relation; is there any way to specify this?
Besides tableName Bookshelf.js also provides an idAttribute property. That will allow you to override Bookshelf.js' id default.
Note the second argument of the relationship (like your hasOne()) is the foreign key, not the target's primary key.
Example:
var Language = bookshelf.Model.extend({
tableName: 'languages',
idAttribute: 'languageid'
});
var Post = bookshelf.Model.extend({
tableName: 'posts',
idAttribute: 'postid',
Language: function() {
return this.belongsTo(Language,'languageid');
}
});
I'm using bookshelf.js as my ORM for node. I have 2 models
Post = bookshelf.Model.extend({
tableName: 'posts',
categories: function () {
return this.belongsToMany('Category');
}
});
Category = bookshelf.Model.extend({
tableName: 'categories',
posts: function () {
return this.belongsToMany('Post');
}
});
They are related via categories_posts table, so its a many to many relationship.
Now I want the user to be able to view all posts in certain category. But I dont want just all posts, I want pagination. But I'm unable to fetch the total posts under specific category, it always returns the total posts that exists in the system.
I've tried this Category.forge({id: id}).posts().query().count('*').then(function(total) {}); but total equals the total posts in posts table as opposed to total posts under category identified by id. Is this even possible, or I should make a helper method that directly queries the categories_posts table?
Thanks.
Ok I think I found a solution.
Category.forge({id: id}).fetch({withRelated: [{posts: function(q) {
q.count('* AS count');
}}]})
.then(function(total) {
console.log(total.toJSON().posts[0].count);
});
Will give the correct value of posts under category identified by id.