Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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"
like image 408
Moradof Avatar asked Feb 06 '18 09:02

Moradof


3 Answers

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.

like image 135
Moradof Avatar answered Nov 18 '22 06:11

Moradof


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

order:[[{ model: db.models.ProductLanguage, as: 'language_of_product' } , 'name', 'desc']]
like image 40
itsHarshad Avatar answered Nov 18 '22 06:11

itsHarshad


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.

like image 1
user3207874 Avatar answered Nov 18 '22 05:11

user3207874