1

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

ilrock
  • 95
  • 4

0 Answers0