Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested preload with limit #5236

Open
Mrbeyond opened this issue Apr 9, 2022 · 6 comments
Open

Nested preload with limit #5236

Mrbeyond opened this issue Apr 9, 2022 · 6 comments
Assignees
Labels
type:question general questions

Comments

@Mrbeyond
Copy link

Mrbeyond commented Apr 9, 2022

Your Question

I want to perform a limit on a nested preload to improve performance. The limit works on the total count on the children but I want the limit to work on each distinct owner.

The models are:

type User struct {
	ID                 uint64   
	Fullname           string     
	Email              string    
        Work               []Work  
}

type Work struct {
	ID           uint64       
	CompanyName  string      
	UserID       uint64       
	User         *User       //  belongs to is needed here
	Project      []Project     
}
type Project struct {
	ID          uint64        
	Role        string  
	Description string   
	WorkID      uint64       
}

Query without Limit:

db.Where("email = ?","myemail@mail.com").
		Preload("Work",  func(db *gorm.DB) *gorm.DB {
			return db.Preload("Project").
				Order("works.id DESC")
		}).
		Find(&user)

Result:

"user": {
		"fullname": "Beyond Beyond",
		"email": "mrbeyond4@gmail.com",
		"works": [
	              {
			     "company_name": "Paycoins",
			      "user": null,
			     "projects": [
			         {
				    "role": "Full stack engineer",
				     "description": "Client app for cryptocurrency payment",
				 },
			        {
				    "role": "Full stack engineer",
				     "description": "Checkout app for cryptocurrency payment",
			       },
			       {
				     "role": "Full stack engineer",
				     "description": "Web hook plugin for api integration",
			      }
		          ]
		   },
	           {
		          "company_name": "Medillery",
			   "user": null,
			    "projects": [
			         {
				     "role": "Full stack engineer",
				     "description": "Client app for creating and assigning projects",						
			         },
			        {
				    "role": "Fronted engineer",
			            "description": "Client app for creating and assigning projects",
			        }
		            ]
		   }
	     ],
         }

Query used to Limit Projects assocatied with Work to just one:

db.Where("email = ?","myemail@mail.com").
		Preload("Work",  func(db *gorm.DB) *gorm.DB {
			return db.Preload("Project",  func(pjdb *gorm.DB) *gorm.DB {
				return pjdb.Limit(1).
				       Order("projects.id DESC")
				 } ).
				Order("works.id DESC")
		}).
		Find(&user)

Result:

"user": {
"user": {
		"fullname": "Beyond Beyond",
		"email": "mrbeyond4@gmail.com",
		"works": [
	              {
			     "company_name": "Paycoins",
			      "user": null,
			     "projects": [
			         {
				    "role": "Full stack engineer",
				     "description": "Client app for cryptocurrency payment",
				 },
			        {
				    "role": "Full stack engineer",
				     "description": "Checkout app for cryptocurrency payment",
			       },
			       {
				     "role": "Full stack engineer",
				     "description": "Web hook plugin for api integration",
			      }
		          ]
		   },
	           {
		          "company_name": "Medillery",
			   "user": null,
			    "projects": [  ]  ## Issue No project fetched here due to limit 1, I want a single project fetched here as well.
		   }
	     ],
         }

The Issue:

It limits total project fetched to just one instead one to each work.

Expected answer:

"user": {
		"fullname": "Beyond Beyond",
		"email": "mrbeyond4@gmail.com",
		"works": [
	              {
			     "company_name": "Paycoins",
			      "user": null,
			     "projects": [
			         {
				    "role": "Full stack engineer",
				     "description": "Client app for cryptocurrency payment",
				 }
		          ]
		   },
	           {
		          "company_name": "Medillery",
			   "user": null,
			    "projects": [
			         {
				     "role": "Full stack engineer",
				     "description": "Client app for creating and assigning projects",						
			         }
		            ]
		   }
	     ],
         }

I seriously need help with this.

Thanks.

@Mrbeyond Mrbeyond added the type:question general questions label Apr 9, 2022
@github-actions
Copy link

github-actions bot commented Apr 5, 2023

This issue has been automatically marked as stale because it has been open 360 days with no activity. Remove stale label or comment or this will be closed in 180 days

@mnussbaum
Copy link
Contributor

This is still an active issue for me

@a631807682
Copy link
Member

a631807682 commented Apr 11, 2023

First of all, before the latest version, we do not support nested preload, and secondly, the currently supported method should be

Preload("Work", func(db *gorm.DB) *gorm.DB {
                    ...
}). Preload("Work.Project")

#6137

cc @black-06

@mnussbaum
Copy link
Contributor

@a631807682 thanks for the pointer to that PR! Does the new syntax allow a limit to be applied to the Project in Work.Project?

@black-06
Copy link
Contributor

black-06 commented Apr 13, 2023

DB.Where("email = ?", "user").
	Preload("Work").
	Preload("Work.Project", func(tx *gorm.DB) *gorm.DB {
		return tx.Limit(1).Order("projects.id DESC")
	}).
	Find(&rst).Error

SQL is

SELECT * FROM `projects` WHERE `projects`.`work_id` IN (1,2) ORDER BY projects.id DESC LIMIT 1
SELECT * FROM `works` WHERE `works`.`user_id` = 1
SELECT * FROM `users` WHERE email = "user"

But it only has one Project in all Works.


Try group by work_id:

DB.Debug().
	Where("email = ?", "user").
	Preload("Work").
	Preload("Work.Project", func(tx *gorm.DB) *gorm.DB {
		return tx.Group("work_id")
	}).
	Find(&rst).Error
// SELECT * FROM `projects` WHERE `projects`.`work_id` IN (1,2) GROUP BY `work_id`

@a631807682
Copy link
Member

It seems that we have no way to set the limit number of each subset in a query, @mnussbaum what is the raw sql you want?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question general questions
Projects
None yet
Development

No branches or pull requests

5 participants