Objection.js is being removed from the application I'm working on. This leaves us with plain knex as query builder. I have now a complex objection query that eager loads a bunch of tables
const adCampaign = await super.getById(id, {
eager: `[
fbAdAccount,
digitalAssets,
fbAdCampaigns.[
fbAdSets.[
fbAdCreatives.[
digitalAsset,
fbAds
]
]
],
twAdCampaigns.[
twAdGroups.[
twWebsiteCards.[
digitalAsset,
twPromotedTweets
]
]
]
]`
})
I was now trying to convert this to knex (to be fair knex can't do this stuff so I'm writing plain postgres) and this is what I started drafting
const campaigns = await this.conn('ad_campaigns')
.select(this.conn.raw(`
COALESCE(
json_agg((
SELECT x FROM (
SELECT fb_ad_campaigns.*,
COALESCE(
json_agg(DISTINCT fb_ad_sets) FILTER (WHERE fb_ad_sets.id is not null), '[]'
) as "fbAdSets"
) as x
)), '[]'
) as "fbAdCampaigns"
`))
.joinRaw(`
LEFT JOIN fb_ad_campaigns on ad_campaigns.id = fb_ad_campaigns."adCampaignId"
LEFT JOIN fb_ad_sets on fb_ad_campaigns.id = fb_ad_sets."fbAdCampaignId"
`)
However, already at the very first sub-eager load (FbAdSets inside FbAdCampaigns) I get this postgres error
error: aggregate functions calls cannot be nested
I presume this refers to the use of COALESCE
and/or json_agg
inside of the subquery that is selecting from fb_ad_sets
.
The easy way out would be to get all the first level tables using json_agg
(fbAdCampaigns
, twAdCampaigns
) and then loop through each of them and get their related tables until I get to the last layer.
Although this would be easier, I'm not sure it would be very efficient