I’ve been trying to achieve a 4 way to join/filter based on 4 tables “Offers”, “UserPaymentMethods” and a junction table “OffersUserPaymentMethods” defined as below;
So I want to filter “offers” based on payment_method_id
because offer_id
lives in offers_user_payment_methods
which makes it a bit tricky. Front-end will send payment_method_id
and I need to filter offers based on the payment_method_id
that’s it.
CREATE TABLE `offers_user_payment_methods` ( `offer_id` bigint(20) unsigned NOT NULL, `user_payment_method_id` bigint(20) unsigned NOT NULL )
CREATE TABLE `offers` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `user_uid` longtext NOT NULL, `base` varchar(20) NOT NULL, `quote` varchar(20) NOT NULL, `side` longtext NOT NULL, `price` decimal(32,16) NOT NULL, `origin_amount` decimal(32,16) NOT NULL, `available_amount` decimal(32,16) NOT NULL, `min_order_amount` decimal(32,16) NOT NULL, `max_order_amount` decimal(32,16) NOT NULL, `payment_time_limit` bigint(20) unsigned NOT NULL, `state` longtext NOT NULL, `created_at` datetime(3) DEFAULT NULL, `updated_at` datetime(3) DEFAULT NULL )
CREATE TABLE `user_payment_methods` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `user_uid` longtext NOT NULL, `payment_method_id` bigint(20) unsigned DEFAULT NULL, `data` json DEFAULT NULL, `created_at` datetime(3) DEFAULT NULL, `updated_at` datetime(3) DEFAULT NULL, )
CREATE TABLE `payment_methods` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `type` longtext NOT NULL, `bank_name` longtext NOT NULL, `logo` longtext NOT NULL, `options` json DEFAULT NULL, `enabled` tinyint(1) NOT NULL, `created_at` datetime(3) DEFAULT NULL, `updated_at` datetime(3) DEFAULT NULL )
Advertisement
Answer
You will struggle to do this efficiently and entirely with Gorm. Preloading/associations aren’t done using join
s in Gorm and there is no way to filter based on them. I see two potential options:
1. Write your own query using join
s and scan in the results
You can use Gorm for the query and execution, but honestly, I would just avoid all the need for reflection etc and just define a struct and scan straight into that.
The results will contain duplicated data, so you will have to manually transpose the results and build up the object.
3. Execute two queries, one to find the IDs of the offers, and one to find the offers
The first query would be the equivalent of:
SELECT offers_user_payment_methods.offer_id FROM offers_user_payment_methods INNER JOIN user_payment_methods ON offers_user_payment_methods. user_payment_method_id = user_payment_methods.id WHERE user_payment_methods.payment_method_id = ?
If you scan these results into var offerIDs []int
, you can use Gorm to find the offers by passing this slice as the param:
offers := make(Offer, 0) db.Find(&offers, offerIDs)
I think this solution has the benefit of you do the more complex query and leave the easy stuff to Gorm (which is what it does ~ok).