Call Model in Model


#1

Hi everybody,
I have a model Group and I want to create a method that calculates the price for every user in a group. The problem is I have to call the pivot table at the Group model and I have a lot trouble with that…
Anyway I found traits and I thought maybe that’s the solution for my problem but I still don’t get further…

Group Model:

class Group extends Model {

    static boot () {
        super.boot()
        this.addTrait('PriceCalculation')        
    }

    users() {
        return this
        .belongsToMany('App/Models/User')
        .withTimestamps()
    }
}

Trait:

Model.queryMacro('getPrice', function (value) {

      this.users()

      return this
    })

But it gives me back:
“this.users is not a function”

Now I have two questions:

  1. Are traits the right think to solve this problem?
  2. How do I get this right?

#2

Hello Schindzielorz

In your Group model try to create a computed property.
You can get access to users relationship by using this.getRelated('users').
Now you’ll have access to all the users in the group.


#3

Thanks for the help melokki but there are still some things I have trouble with…

That’s what I implemented:

static get computed () {
    return ['user_price']
  }

getPrice ({ price, maxGroupSize }) {

    // try to get members
    const members = this.getRelated('users')
    console.log(members)

    // Price calculation
    const user_price = price / maxGroupSize
    return user_price
}

That’s what I get back:

undefined
Price!!! { id: 1,
  description: 'Test',
  name: 'Test',
  price: NaN,
  maxGroupSize: 5,
  provider_id: 1,
  admin_user: 1,
  created_at: '2018-06-27 09:47:19',
  updated_at: '2018-06-27 09:47:19',
  user_price: null }
  1. “this.getRelated(‘users’)” gives me an undefined back
  2. price have the value NaN but it should be 10
  3. user_price is null

Do you know what I am doing wrong?


#4

the price is stored somewhere else?
do you have a git repo where I can watch the structure?


#5

Thanks for responding. I don’t have a git repo but I hope you can help me without.

The price for a group is coming from the groups table. But the users price is the price for the group divided by all group members.

Group members can join and leave the group when ever they want so the price for the members is constantly changing. That is the reason why I want to make the calculation in a separated method or something.


#6

Can you post the content of your user and group models?
I am not able to help you very well without seeing some code


#7

Group Model:

'use strict'

const Model = use('Model')

class Group extends Model {

// Test for price calculation 
    static get computed () {
        return ['user_price']
      }

    setUser_Price ({ user_price }) {

        // try to get members
        const members = this.getRelated('users')
        console.log(members)

        // Price calculation
        user_price = 5
        return user_price
    }

    users() {
        return this
        .belongsToMany('App/Models/User')
        .withTimestamps()
    }

    orders() {
        return this
        .belongsToMany('App/Models/Order')
        .withTimestamps()
      }

    group_requests () {
    return this.hasOne('App/Models/GroupRequest')
    }
}

module.exports = Group

User Model:

'use strict'

const Hash = use('Hash')
const Model = use('Model')

class User extends Model {
  static boot () {
    super.boot()

    /**
     * A hook to hash the user password before saving
     * it to the database.
     */
    this.addHook('beforeCreate', async (userInstance) => {
      if (userInstance.dirty.password) {
        userInstance.password = await Hash.make(userInstance.password)
      }
    })
  }

  /**
   * A relationship on tokens is required for auth to
   * work. Since features like `refreshTokens` or
   * `rememberToken` will be saved inside the
   * tokens table.
   *
   * @method tokens
   *
   * @return {Object}
   */
  tokens () {
    return this.hasMany('App/Models/Token')
  }

  // Computed propertie for full name
  static get computed () {
    return ['fullname']
  }

  getFullname ({ firstName, lastName }) {
    return `${firstName} ${lastName}`
  }

  // User -> Group relationship
  groups() {
    return this
    .belongsToMany('App/Models/Group')
    .withTimestamps()
  }

  admins() {
    return this.hasMany('App/Models/Group')
  }

  addresses() {
    return this
    .belongsToMany('App/Models/Address')
    .withTimestamps()
  }

  group_requests () {
    return this.hasMany('App/Models/GroupRequest')
  }

  

}

module.exports = User

#8

Try something like this in your Group model

  static get computed () {
    return ['user_price']
  }

setUserPrice () {
    // try to get members
    const members = this.getRelated('users')
    console.log(members.rows) // you should have all the users here as an array
    console.log(members.rows.length) // how many users the group has

    // Price calculation
    user_price = 5
    return user_price
}

I have’t tested the code, but according to what I previously did you should see some results


#9
    const members = this.getRelated('users')
    console.log(members) // undefined
    console.log('TEST!!!',members.rows.length) // It doesn't  know rows or length
    console.log('TEST!!!') // to test if it gets in
    return members

I thought maybe the way how I call it is wrong… so I was was testing a bit but without results

const group = await Group.find(1)
const price =  group.setUser_Price()
const test = group.toJSON()
console.log('setUser',price) // direct call => undefined
console.log('Test',test) // toJSON() => same result then before 

I just want to say I really appreciate your help!!


#10

I see a typo in your computed property method name, it should be getUserPrice instead of setUser_Price
Also in my previous post it should be getUserPrice instead of setUserPrice


#11

That was progress :slight_smile:

I finally can set a user_price!
The downside is, I still cant access the users…

const members = this.getRelated('users')
console.log(members) // undefined 
console.log(members.rows) // Cannot read property 'rows' of undefined
console.log('TEST!!!')

I am surprised that the naming convention makes such a big deference


#12

Do you know where I can find the documentation for that?


#13

unfortunately not, I discovered this function going trough adonis source code.
I saw user virk mentioning this function in on of his posts also.

I don’t have too much time this week to try to recreate this on my local machine, but will try on weekend to see what is going on.


#14

I was searching in the forum and in the documentation for this without any results. But it would be great if it works that easy.
Thanks for doing that


#15

hello @Schindzielorz

I’ve managed to make some time to test this and indeed this.getRelated is not working, I can’t explain you why because I don’t know :frowning:
but I was thinking, why don’t you calculate the user price on the User model itself? after all it’s something specific to a user and not to a group.
there you will have access to user groups and to the group price and I think you can get access to the number of users into that group too.

In the User model you can do this:

  static get computed () {
    return ['user_price']
  }

  getUserPrice () {
    this.getRelated('groups').rows.map((Group) => {
        console.log(Group)
        console.log(Group.price)
    })
  }

#16

Thank you @melokki for trying, I really appreciate it.

I can’t put it in the User model because I want to calculate the price for every user in the group and not for one specific user. That makes it group related.
And even if it would be user related I would have the same problem, right?
I think I just have to keep searching for a solution…

If I find something I will let you know