Objection.js: Selecting certain fields in eager loading

Created on 14 Nov 2018  路  2Comments  路  Source: Vincit/objection.js

const {
  Model,
} = require('../../config/db');

class Airport extends Model {
  static get tableName() {
    return 'airports';
  }

  static get idColumn() {
    return 'id';
  }

  static get relationMappings() {
    return {
      departingFlights: {
        relation: Model.ManyToManyRelation,
        modelClass: `${__dirname}/flight.model`,
        join: {
          from: 'airports.id',
          through: {
            from: 'flightSchedules.departure_airport_id',
            to: 'flightSchedules.flight_id',
          },
          to: 'flights.id',
        },
      },
      arrivingFlights: {
        relation: Model.ManyToManyRelation,
        modelClass: `${__dirname}/flight.model`,
        join: {
          from: 'airports.id',
          through: {
            from: 'flightSchedules.arrival_airport_id',
            to: 'flightSchedules.flight_id',
          },
          to: 'flights.id',
        },
      },
    };
  }
}

module.exports = Airport;
const {
  Model,
} = require('../../config/db');

class Flight extends Model {
  static get tableName() {
    return 'flights';
  }

  static get idColumn() {
    return 'id';
  }

  static get relationMappings() {
    return {
      flightSchedules: {
        relation: Model.HasManyRelation,
        modelClass: `${__dirname}/flightSchedule.model`,
        join: {
          from: 'flights.id',
          to: 'flightSchedules.flightId',
        },
      },
    };
  }
}

module.exports = Flight;
const {
  Model,
} = require('../../config/db');

class FlightSchedule extends Model {
  static get tableName() {
    return 'flightSchedules';
  }

  static get idColumn() {
    return 'id';
  }

  static get relationMappings() {
    return {
      flight: {
        relation: Model.BelongsToOneRelation,
        modelClass: `${__dirname}/flight.model`,
        join: {
          from: 'flightSchedules.flightId',
          to: 'flights.id',
        },
      },
      departureAirport: {
        relation: Model.BelongsToOneRelation,
        modelClass: `${__dirname}/airport.model`,
        join: {
          from: 'flightSchedules.departureAirportId',
          to: 'airports.id',
        },
      },
      arrivalAirport: {
        relation: Model.BelongsToOneRelation,
        modelClass: `${__dirname}/airport.model`,
        join: {
          from: 'flightSchedules.arrivalAirportId',
          to: 'airports.id',
        },
      },
    };
  }
}

module.exports = FlightSchedule;



md5-7e34305c1138667016b3560dd1e1c552



const flights = await Flight
    .query()
    .eager({
      flightSchedules: {
        departureAirport: true,
        arrivalAirport: true,
      },
    })
    .omit(['flightSchedules.id'])
    .eagerAlgorithm(Flight.JoinEagerAlgorithm);



md5-d86f987f46159c5db8cfc981821e7539



{
    "flights": [
        {
            "id": 1,
            "flightstatsId": "1",
            "flightCarrier": "AI",
            "flightNumber": "142",
            "createdAt": "2018-11-14T19:39:33.886Z",
            "updatedAt": "2018-11-14T19:39:33.886Z",
            "flightSchedules": [
                {
                    "id": 1,
                    "flightId": 1,
                    "departureAirportId": 2,
                    "arrivalAirportId": 1,
                    "departureTime": "2018-11-25T00:00:00.000Z",
                    "arrivalTime": "2018-11-25T01:00:00.000Z",
                    "createdAt": "2018-11-14T19:40:27.454Z",
                    "updatedAt": "2018-11-14T19:40:27.454Z",
                    "departureAirport": {
                        "id": 2,
                        "fs": "CDG",
                        "iata": "CDG",
                        "icao": "CDG",
                        "faa": null,
                        "name": null,
                        "street1": null,
                        "street2": null,
                        "city": null,
                        "cityCode": null,
                        "district": null,
                        "stateCode": null,
                        "postalCode": null,
                        "countryCode": null,
                        "countryName": null,
                        "regionName": null,
                        "timezoneRegionName": null,
                        "weatherZone": null,
                        "utcOffsetHours": null,
                        "location": null,
                        "elevationFeet": null,
                        "active": null
                    },
                    "arrivalAirport": {
                        "id": 1,
                        "fs": "DEL",
                        "iata": "DEL",
                        "icao": "DEL",
                        "faa": null,
                        "name": null,
                        "street1": null,
                        "street2": null,
                        "city": null,
                        "cityCode": null,
                        "district": null,
                        "stateCode": null,
                        "postalCode": null,
                        "countryCode": null,
                        "countryName": null,
                        "regionName": null,
                        "timezoneRegionName": null,
                        "weatherZone": null,
                        "utcOffsetHours": null,
                        "location": null,
                        "elevationFeet": null,
                        "active": null
                    }
                }
            ]
        },
        {
            "id": 2,
            "flightstatsId": "2",
            "flightCarrier": "AI",
            "flightNumber": "143",
            "createdAt": "2018-11-14T19:39:38.069Z",
            "updatedAt": "2018-11-14T19:39:38.069Z",
            "flightSchedules": []
        }
    ]
}

I am not able to omit certain fields like departureAirportId, arrivalAirportId, id in the flightSchedules.

Can this be done?

Most helpful comment

There are multiple ways to achieve that. Which one is the best depends on your use case (do you want to always omit the fields? do you want to omit them only in some cases?)

  1. define modifiers for models:
// Define a modifier (for example by the name `defaultSelects`) for each model:
class Airport extends Model {
  static get modifiers() {
    defaultSelects: builder => builder.select('all', 'your', 'columns', 'you', 'want', 'to', 'select')
  }
}

const flights = await Flight
    .query()
    // This applies the modifier for the root query.
    .modify('defaultSelects')
    .joinEager({
      flightSchedules: {
        $modify: ['defaultSelects']
        departureAirport: {
          $modify: ['defaultSelects']
        },
        arrivalAirport: {
          $modify: ['defaultSelects']
        }
      }
    })
  1. Use the two-argument version of omit
const flights = await Flight
    .query()
    .joinEager({
      flightSchedules: {
        departureAirport: true,
        arrivalAirport: true,
      },
    })
    .omit(['id'])
    .omit(Airport, ['id'])
    .omit(FlightSchedule, ['id'])

You can also create a modifier that adds the omit fields, so that you don't need to add all of those each time. You could simple say something like .modify('omitIdentifiers')

  1. Use modifyEager
const flights = await Flight
    .query()
    .joinEager({
      flightSchedules: {
        departureAirport: true,
        arrivalAirport: true
      }
    })
    .modifyEager('flightSchedules.departureAirport', builder => builder.select('all', 'fields', 'you', 'want', 'to', 'keep')

Again, you can create a modifier that calls the modifyEager methods.

All 2 comments

There are multiple ways to achieve that. Which one is the best depends on your use case (do you want to always omit the fields? do you want to omit them only in some cases?)

  1. define modifiers for models:
// Define a modifier (for example by the name `defaultSelects`) for each model:
class Airport extends Model {
  static get modifiers() {
    defaultSelects: builder => builder.select('all', 'your', 'columns', 'you', 'want', 'to', 'select')
  }
}

const flights = await Flight
    .query()
    // This applies the modifier for the root query.
    .modify('defaultSelects')
    .joinEager({
      flightSchedules: {
        $modify: ['defaultSelects']
        departureAirport: {
          $modify: ['defaultSelects']
        },
        arrivalAirport: {
          $modify: ['defaultSelects']
        }
      }
    })
  1. Use the two-argument version of omit
const flights = await Flight
    .query()
    .joinEager({
      flightSchedules: {
        departureAirport: true,
        arrivalAirport: true,
      },
    })
    .omit(['id'])
    .omit(Airport, ['id'])
    .omit(FlightSchedule, ['id'])

You can also create a modifier that adds the omit fields, so that you don't need to add all of those each time. You could simple say something like .modify('omitIdentifiers')

  1. Use modifyEager
const flights = await Flight
    .query()
    .joinEager({
      flightSchedules: {
        departureAirport: true,
        arrivalAirport: true
      }
    })
    .modifyEager('flightSchedules.departureAirport', builder => builder.select('all', 'fields', 'you', 'want', 'to', 'keep')

Again, you can create a modifier that calls the modifyEager methods.

@koskimas Is there any way I can ignore results by specifying conditions on relations.
For example, I have this: https://gist.github.com/abhyuditjain/662bd103706a9fdb8457faadb9bbe79f
In this I am trying to fetch all the flightSchedules but only want results where departureAirport.iata is "DEL". I have defined the models, query and the output in the gist.

Thanks for helping with the previous query.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nicolaracco picture nicolaracco  路  3Comments

njleonzhang picture njleonzhang  路  4Comments

apronin83 picture apronin83  路  3Comments

falkenhawk picture falkenhawk  路  4Comments

AhmadRaza786 picture AhmadRaza786  路  3Comments