There are two tables, Books which has many-to-many association with Tags.
How can the Book that have only particular tag id be found?
I tried:
Book.find().populate("tag", where:{id: 1 }).exec(console.log)
But it gives all the books.
If your looking for all books with a specific tagid, your going to want to do something like:
Tag
.findOne(1)
.populate('books')
.then(function(tag) {
if (!tag) {
res.serverError(error);
} else {
res.json(tag.books);
}
});
Basically you want to look up the tag by id (1), and then populate the books association for that tag.
You must provide criteria in find(), not in populate.
Your fixed variant:
Book
.find()
.where({
id: 1
})
.populate('tag')
.exec(function(error, books) {
if (error) {
res.serverError(error);
} else {
res.json(books);
}
});
Related
I am using prisma + mysql (on planetscale). When I link two items that are in different tables, I normally use connect or disconnect:
const getUser = await prisma.user.update({
where: {
id: 9
},
data: {
posts: {
| connect: {
| id: 11
| },
create: {
title: "My new post title"
}
}
}
})
I am wondering whether that's necessary or why that's necessary?
I also noticed that I can just update records in my database by updating the id (as a plain string), and it will still work. e.g.:
// example for updating a one-to-many relationship:
const getUser = await prisma.user.update({
where: {
id: 9
},
data: {
postId: "123192312i39123123"
}
}
})
... or if it's an explicit many-to-many relation, I can just edit the row in the relation-table & update the id.
Is this a bad way of doing things? Am I going to break something later down the line in doing it this way?
Your cloud provider is not relevant in the context of the question. It will not affect how your framework(prisma) behaves in updates.
I am wondering whether that's necessary or why that's necessary?
You have a user with a one to many relation: user => n posts.
You have an existing post in the db, and you want to add that post to the posts collection of a user.
That posts relation can be either explicit or implicit. The connect clause handles the addition of relation:
{
posts: {
connect: { id: 11 }
}
}
Without using the connect you'd have to create a new post:
{
posts: {
create: {
title: "My new post title"
}
}
}
update records in my database by updating the id (as a plain string)
Not sure what you mean here, mind sharing the schema?
or if it's an explicit many-to-many relation, I can just edit the row in the relation-table & update the id
If it's explicit many-to-many then it's OK to manually edit the id fields. As long as the ids are found and the relation makes sense, there's no problem with manual updates.
I have two tables: notes and tags, related by note_tags
.createTable('notes', function (table) {
table.increments('id').primary()
table.string('title', 100).notNullable()
table.string('content', 300).notNullable()
table.boolean('archived').notNullable().defaultTo(false)
table.timestamp('updated_at').defaultTo(knex.raw('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'));
})
.createTable('tags', function (table) {
table.increments('id').primary()
table.string('name', 20).notNullable()
})
.createTable('note_tags', function (table) {
table.increments('id').primary()
table.integer('note_id').unsigned().notNullable()
table.integer('tag_id').unsigned().notNullable()
table.foreign('note_id').references('notes.id')
table.foreign('tag_id').references('tags.id')
})
I want to get all the "used" tags, the ones that have at least one relation with any note
I don't know much about SQL, and with help of copilot i tried with:
async getUsedTags() {
return await Tag.query()
.select('tags.*')
.join('notes_tags', 'tags.id', 'notes_tags.tag_id')
.join('notes', 'notes.id', 'notes_tags.note_id')
.where('notes.archived', false)
}
but it returns "ER_NO_SUCH_TABLE: Table 'ensolvers-challenge.notes_tags' doesn't exist"
I am quite new to sequelize and mySQL and feel like I have tried everything in order to pass a search term ('query') to both the books table (searching against titles) and the authors table (searching against first_name or last_name). In the event of matching any of those values substrings it is to return the whole book and author information as a JSON object. When I just have the query focused on book title, it returns everything just fine. The problem comes in when I try to pass in Author columns. I have tried aliasing, nesting where clauses, everything I can think of to do and nothing I come across on here or online seems to help me figure it out.
search: (req, res) => {
const { query } = req.query;
Book.findAll({
include: [Author],
where: {
[Op.or]: [
{ title: { [Op.substring]: query } },
]},
})
.then((Book) => res.json(Book))
.catch((err) => {
console.log(err);
res.status(500).json(err);
});
},
Here is the working code. In the where clause, I want to do { first_name: { [Op.substring]: query } }, for example but it isn't accessing the Author table. In the include statement I have tried aliasing and calling it in the where clause, but that throws a aliasing error saying I have already declared an alias (Author) but when I try to use that as { 'Author.first_name' { [Op.substring]: query } }, it returns that there is no Book.Author.first_name.
I am probably missing something simple, so anyone that might be able to help, let me know what I am doing wrong here!
Solved and it was super easy. I was missing the syntax for accessing the separate table which is '$Author.first_name$'.
I've read this question and it didnt' help me, so I'm asking my own:
Let's suppose I have 2 tables joined by a NM through table using Sequelize and MariaDB:
User <-- UserItem --> Item
A single User can have many Items, and a single Item can belong to many Users. But I need a custom through attribute to store the quantity of the Item, let's call it Apples. So, according to the docs, this will be the definition:
var UserItem = Sequelize.define('UserItem', {
quantity: DataTypes.INTEGER
},
timestamps: false
});
models.Item.belongsToMany(models.User, {through: 'UserItem'});
models.User.belongsToMany(models.Item, {through: 'UserItem'});
And then I add a new relationship with the through attribute like this:
User.addItem(item, { quantity: 0 });
This works as expected. But, what if I need to update the quantity of an Item? I could do the following:
User.addItem(item, { quantity: 20 });
And the quantity of my Item will be updated to 20 in case of existing, and inserted otherwise. I don't want this. I want something like that:
User.addItem(item, { quantity: quantity + 1 });
But due to the impossibility to make queries to the join tables, I am unable to get the particular NM row for updating using the previous value.
How can I achieve this? Thanks in advance.
You still have the join table DAO as specified in the docs.
In this case though you need to know if the item is new association or not.
So it will look something like.
User.hasItem( item )
.then( exists => {
if ( !exists ) {
return User.addItem( item, { quantity : 20 } )
} else {
item.UserItem.quantity += 1;
return item.UserItem.save();
}
} )
You can read more about hasAssociation in the docs as well.
Using Laravel 5.1: Given two related models, User and Item, with through table Item_User, how can I include a specific column from the through table, item_count using a with statement?
Item_User table:
Query:
$userGameProfile = User::with([
'items' => function($query) use ($profile_id) {
$query->with(['phrases'])->where('profile_id', '=', $profile_id);
}])->find($id);
Adding ->select('item_count') to this query only returns item count, and not the related item objects. Adding ->select('*') gets me the items and fields I want, but breaks the nested with(['phrases']) relationship I need to get related phrases to items.
I was told I should use withPivot, but I cannot find documentation or examples on how to use this.
Preferably, I'd like to add this to the relationship, rather than each query.
Models:
User:
public function items()
{
return $this->belongsToMany(Item::class, 'user_item');
}
Item:
public function users()
{
return $this->belongsToMany(User::class, 'user_item');
}
public function phrases()
{
return $this->belongsToMany(Phrase::class, 'item_phrase');
}
Phrase:
public function items()
{
return $this->belongsToMany(Item::class, 'item_phrase');
}
This article highlights how to include additional information from the pivot table.
In User model, I know I will always want to include item_count from user_items pivot table, so you can add withPivot to the relation to items:
public function items()
{
return $this->belongsToMany(Item::class, 'user_item')
->withPivot('item_count');
}
User now comes back with items and pivot data: