sequelize: Load/include association for already existing instance
Not sure if this is possible. So I can fetch associations when I am finding object via include
:
models.User.find({ where: { id: 1 }, include: [models.Avatar]).then(function(user) {
user.Avatar // will have avatar object associated with user object.
});
But when I am creating user and use setter to set association, how to get user
object in the end to have user.Avatar
?
user.setAvatar(avatar).then(function(user) {
user.Avatar // not defined?
});
Should I always manually assign object after setting relationship?
About this issue
- Original URL
- State: open
- Created 9 years ago
- Reactions: 48
- Comments: 27 (9 by maintainers)
Please don’t +1 issues. It clutters the thread without adding value to the discussion and spams maintainers with notifications. Use GitHub reactions to upvote features.
I’m shocked that Sequelize doesn’t support this feature. As PHPer before, we benefit this feature provided by Eloquent ORM in Laravel for a long time. I prefer to borrow the
load
API from Eloquent for loading nested associations with the same queries syntax as Sequelize. For example,Comparing to lazy load mentioned above, it would be easier to load all related associations in one call and optimize the SQL queries as much as possible.
Is this still on the roadmap? It seems very counter-intuitive that lazy loaded data is not actually stored in the parent model, making it kind of pointless since it requires re-running queries every time when you want to access the data.
Instead of:
To have:
I made myself a
lazyload()
helper function as a stopgap. (Written in TypeScript)And in the same area, it would be nice if, following a lazy loading, the result would be stored in the instance. Actually, it might be a little more complicated than that as it’s the lazy loading mechanism that could be improved.
For example, I have various controllers that load an object and they all pass it to a common utility method to convert that object into a JSON for the HTTP response. In this utility, I often need to read the relations of the entity and I can’t be sure that the controller code loaded all the required relations. To avoid issuing another query to the database if the relation is already loaded, I do something like: return Promise.props( id: team.id name: team.name manager: if team.Manager? then UserService.getBasicUserForView( team.Manager ) else team.getManager().then (manager)-> UserService.getBasicUserForView( manager ) league: if team.League? then LeagueService.getBasicLeagueForView( team.League ) else team.getLeague().then (league)-> LeagueService.getBasicLeagueForView( league ) # Get players and we will convert them later players: team.Players ? team.getPlayers() )
It would be nice if: 1 - team.getManager would automatically persist the result into team.Manager so if for some reason that relation is used again, it would be already loaded 2 - team.getManager skipped the database query if the object was already loaded
That way, I could simply do the following and the database would be hit only if needed: return Promise.props( id: team.id name: team.name manager: team.getManager().then (manager)-> UserService.getBasicUserForView( manager ) league: team.getLeague().then (league)-> LeagueService.getBasicLeagueForView( league ) # Get players and we will convert them later players: team.Players ? team.getPlayers() )
I can see some problems when filters are used in the getter for toMany relations. The rule could be that the getter set the relation property if no filter was applied. Also, the getter would return the cached value if the getter is called without any filter. There could also be an option in the getter to force a dabase read.
I’m coming from java and hibernate and I assumed that this is how it was already implemented. I was surprised when I looked at the query log and realized that the lazy loaded associations are not kept in memory after the lazy init.
BTW, great work guys. I just finished migration my project from waterline to Sequelize and there is no looking back. This project and your support is amazing.
Manuel
On 29 March 2015 at 15:44, Pavel Karoukin notifications@github.com wrote:
@matthewstrom that worked nicely! Added it to all classes
Any update on this? I know it’s been a while For the moment, I’m forced to do something like this if I want to make sure I don’t hit the DB unnecessarily
I think it could easily be implemented as an option in the getter. Just pass
{ lazy: true }
or something and the getter just resolves the cached value if presentThis is exactly what my point was, it feels like you need to just do way too much work to get associated values out sometimes.
Surely building against the base item is a better way of doing things, rather than separate entities.
With active record a call of ‘author.books’ just means you have access to the authors books right away.
Maybe, its just that the sequelize documentation is poor, I came from years of Rails, and every single Node ORM I tried playing with seemed to have a clear lack of good, clear documentation. Sequelize was the best, but still lacking. (Active Record association docs for reference: http://guides.rubyonrails.org/association_basics.html)
Again, I’m not trying to shit on the work you guys are doing, however, I think a lot could be learned from more mature libraries. 😃
On Tue, Dec 5, 2017 at 10:31 AM darkalor notifications@github.com wrote:
It seems
model.$get('association')
is what we were looking for, as inuser.$get('comments')
wherecomments
is the name of the association, not the model. At least if you usesequelize-typescript
, it is documented here: https://github.com/sequelize/sequelize-typescript#type-safe-usage-of-auto-generated-functionsIt is very confusing that I can not write an abstract code that suppose to process model associations like:
In order to make this method take benefit of eager loading I would need to check how the comments where loaded into the
user
model:And there is still no guarantee that
user.Comments
is the same as a defined association.The way eager loading is implemented in Sequelize breaks the whole idea of OOD where you expect all instances of the same class to have the same API but not conditional properties depending on how the a class instance was constructed (aka queried).
I think
get<association name>
should always return aPromise
. However, if the association was eager loaded without additional conditions (like customwhere
), it should just reuse that result internally likePromise.relolve(eagerLoadingResult)
.I find that very counter-intuitive, but… okay.
@rsshilli that is as designed.
getDepartments()
is for lazy loading, that is why it is a method and not a property and returns a Promise.user.Departments
is only present if you eager loaded the association throughinclude
.+1
+1
Hey guys any news on this? I’m kinda shocked sequelize doesn’t support this feature… very basic in most ORMs