Moradof
Moradof

Reputation: 483

Sequelize throws Error "Unable to find a valid association for model x" When Ordering By Associated Model

I have a problem with sequelize, when I want to ordering my query result by associated model, sequelize throw this error:

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Unable to find a valid association for model, 'productLanguage'

These are my files:

**Context.js **

const Sequelize = require('sequelize');
const sequelize = new Sequelize("postgres://postgres:123456@localhost:5432/sampleDB");

module.exports = {
    Sequelize: Sequelize,
    sequelize: sequelize
}

User.js

const context = require('../context');

module.exports = context.sequelize.define('user', {
    name: context.Sequelize.STRING,
    },{
    freezeTableName: true
});

Product.js

const context = require('../context');

module.exports = context.sequelize.define('product', {
    slug: context.Sequelize.STRING,
    price: context.Sequelize.DECIMAL(10,2),
    },{
    freezeTableName: true
});

ProductLanguage.js

const context = require('../context');

module.exports = context.sequelize.define('productLanguage', {
    name: context.Sequelize.STRING,
    },{
    freezeTableName: true,
    timestamps: false
});

Language.js

const context = require('../context');

module.exports = context.sequelize.define('language', {
    name: context.Sequelize.STRING,
    slug: context.Sequelize.STRING,
    },{
    freezeTableName: true
});

db.js

var context = require('./context');
var User = require('./models/User'),
    Product = require('./models/Product'),
    ProductLanguage = require('./models/ProductLanguage'),
    Language = require('./models/Language');


// ===================== ASSOCIATIONS =====================
// user 1:m Product
Product.belongsTo(User); // product owner
User.hasMany(Product);

// Product 1:m ProductLanguage m:1 Language
ProductLanguage.belongsTo(Product);
Product.hasMany(ProductLanguage);
ProductLanguage.belongsTo(Language);
Language.hasMany(ProductLanguage);

module.exports = {
    Sequelize: context.Sequelize,
    sequelize: context.sequelize,
    models: {
        Product: Product,
        User: User,
        ProductLanguage: ProductLanguage,
        Language: Language
    }
}

and finally this is my query

app.get('/', async (req, res, next)=>{

    var result = await db.models.User.findAll({
        include:[
            {
                model: db.models.Product,
                attributes: ['price'],
                include: [
                    {
                        model: db.models.ProductLanguage,
                        attributes: ['name'],
                        include: [
                            {
                                model: db.models.Language, 
                                attributes: ['name'],                               
                            }
                        ]
                    }
                ]
            }
        ],
        order:[
            [db.models.ProductLanguage, 'name', 'desc']
        ],
        attributes: ['name']
    });

    res.send(result);
});

The query work fine without "order" part, so I think the problem should be one on these :

  1. Something is wrong on this part: [db.models.ProductLanguage, 'name', 'desc']
  2. Something is wrong on association definitions

Note: I've searched on youtube and stackoverflow and sequelize documentation over 4 days but nothing found.

I use these dependencies:

"express": "^4.16.2",
"pg": "^6.4.2",
"pg-hstore": "^2.3.2",
"sequelize": "^4.32.2"

Upvotes: 12

Views: 8308

Answers (3)

itsHarshad
itsHarshad

Reputation: 1639

Those who still won't get the result, try this syntax -

order:[[{ model: db.models.ProductLanguage, as: 'language_of_product' } , 'name', 'desc']]

Upvotes: 5

user3207874
user3207874

Reputation: 3647

In addition to Moradof's answer, it's important to note that if you specify an alias for your included model, then you must also specify the alias in the order statement.

Building on the previous example, we get:

var result = await db.models.User.findAll({
    include:[
        {
            model: db.models.Product,
            as: 'include1',
            attributes: ['price'],
            include: [
                {
                    model: db.models.ProductLanguage,
                    as: 'include2',
                    attributes: ['name'],
                    include: [
                        {
                            model: db.models.Language, 
                            attributes: ['name'],                               
                        }
                    ]
                }
            ]
        }
    ],
    order:[
        [{ model: db.models.Product, as: 'include1' }, 
         { model: db.sequelize.models.ProductLanguage, as: 'include2' },
         'name',
         'desc']
    ],
    attributes: ['name']
});

Note that because I named the Product as include1 in the include statement, I also had to name it as include1 in the order statement.

Upvotes: 3

Moradof
Moradof

Reputation: 483

I've found the solution.

I must put all associated model into order, so the correct query is:

order:[
        [db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
    ],

The full query must be:

var result = await db.models.User.findAll({
    include:[
        {
            model: db.models.Product,
            attributes: ['price'],
            include: [
                {
                    model: db.models.ProductLanguage,
                    attributes: ['name'],
                    include: [
                        {
                            model: db.models.Language, 
                            attributes: ['name'],                               
                        }
                    ]
                }
            ]
        }
    ],
    order:[
        [db.models.Product, db.sequelize.models.ProductLanguage, 'name', 'desc']
    ],
    attributes: ['name']
});

I hope this will be helpful for others.

Upvotes: 25

Related Questions