Adonis 5 how to get pivot_column from $extras and inject into preload

1k views Asked by At

I created an extra column on my manyToMany decorator and know how to preload my data based on its value. my question is how can I actually take that value and insert it to it's relevant preloaded data or insert them into a new array on parent model, in other words how can I bring back the extra pivot_column with my record(s) because currently it's in the $extra and not showing up with other properties in api call, Im currently creating a new array and inserting it with a map() but Im very worried about this approach.

thank you

4

There are 4 answers

2
w3bsite On BEST ANSWER

so assuming we have a products table in manyToMany relation with colors table

export default class Product extends BaseModel {
@manyToMany(() => Color, {
pivotTable: 'color_products',
pivotTimestamps: true,
pivotColumns: ['stock'],
})
public colors: ManyToMany<typeof Color>
} 

when we bring back a single instance with product.load() or an array with Product.preload()

there will be and array of colors as a product parameter and pivot_table here color_products data in $extras I asked how can I bring the $extras as a product parameter but that was a mistake and the stock(number) is about the color of product for example a I want to know how many green shirts is in the database, as a result the solution will do just that,bringing stock number with each color object as a product parameter.here is how:

export default class Color extends BaseModel {
@manyToMany(() => Product, {
pivotTable: 'color_products',
pivotTimestamps: true,
pivotColumns: ['stock'],
})
public products: ManyToMany<typeof Product>

@computed()
public get stock() {
  const stock = this.$extras.pivot_stock
  return stock
  }
}

Short version

define a computed method on the related model and return the column from this.$extras:

    @computed()
public get stock() {
  const stock = this.$extras.pivot_stock //my pivot column name was "stock"
  return stock
  }

don't forget you should have allready have this in @manyToMany options inside your model:

pivotColumns: ['stock'],

or bring the pivotColumn from other ways.

1
jsdecena On

Not sure why you are making a new array because you can continue the query() instance with map():

      const rewards = await user.related('rewards').query()

      const transformed = rewards.map((reward) => {
        return {...reward.toJSON(), status: reward.$extras.pivot_status}
      })
      
      return response.json({data: transformed})

Though, this is still not good as it is not paginated :( but it works for my case.

1
taco On

you may need this. Additional pivot columns

0
Matheus Sampaio On

You can also serialize the $extras object by defining the following property on the model.

class Post extends BaseModel {
  /**
   * Serialize the `$extras` object as it is
   */
  public serializeExtras = true
}

Also, you can customize the properties you want to pick from the extras object by declaring the serializeExtras property as a function.

class Post extends BaseModel {
  public serializeExtras() {
    return {
      category: {
        name: this.$extras.category_name
      },
    }
  }
}

found here: https://docs.adonisjs.com/guides/models/serializing-models#serializing-extras-object