Sam Hughes
Sam Hughes

Reputation: 153

Loopback "Include" Filter Fails with hasManyThrough Relation

I have 3 models. 2 resource models, account(id, name) and widget(id, name), and 1 mapping model to map between the two widget_to_account(id, account_id, widget_id), to tell what widgets an account has access to, so to speak.

When stating the relationship between the models in their JSONs, using the guide in http://loopback.io/doc/en/lb3/HasManyThrough-relations.html, RESTful requests like "get widgets of account id=1" for example, works perfectly.

GET /accounts/1/widgets yields the widgets that account 1 has, yielding a widgets array:

[
    {
        "id": 1,
        "name": "wg_user_mgr"
    },
    {
        "id": 2,
        "name": "wg_desc"
    }
]

That's all good.

However, say I wanted to append this widgets array result along with the account object returned by a GET to the account model?. Loopback documentation suggests that this is done using the include keyword with the request, like so: GET /accounts/1?filter[include]=widgets, returning hopefully an account model with it's allowed widgets:

{
    "id": 1,
    "name": "Account1Name",
    "widgets": [
        {
            "id": 1,
            "name": "wg_user_mgr",
            "display_name": "User Manager"
        },
        {
            "id": 2,
            "name": "wg_desc",
            "display_name": "Description"
        }
    ]
}

However, what is actually returned by loopback with that request, is:

{
    "id": 1,
    "name": "Account1Name",
    "widgets": []
}

Empty widgets array! When I look at the loopback SQL debugs, I see that it does go to the widget_to_account table and selects the entries of account_id=1, but interestingly it stop there and just returns an empty widgets array.

Any clues? The hasManyThrough loopback docs doesn't actually show any examples of using include like this to bridge two models that are connected via a mapping model.

My guess is they just forgot to code it in ¯\_(ツ)_/¯

UPDATE:

Doing some more digging around, I found the answer at https://groups.google.com/forum/#!topic/loopbackjs/sH7bKoqzU5c.

Where you define the relationships in the 2 resource models, you have to specifically define the "keyThrough" value.

NOT THIS:

"relations": {
    "widgets": {
        "type": "hasMany",
        "model": "widget",
        "foreignKey": "account_id",
        "through": "widget_to_account"
    }
}

BUT THIS:

"relations": {
    "widgets": {
        "type": "hasMany",
        "model": "widget",
        "foreignKey": "account_id",
        "through": "widget_to_account",
        "keyThrough": "account_id"
    }
}

This is not made super clear, and is even stated incorrectly in the loopback api docs -.-

Upvotes: 3

Views: 1269

Answers (1)

Sam Hughes
Sam Hughes

Reputation: 153

UPDATE:

Doing some more digging around, I found the answer at https://groups.google.com/forum/#!topic/loopbackjs/sH7bKoqzU5c.

Where you define the relationships in the 2 resource models, you have to specifically define the "keyThrough" value.

NOT THIS:

"relations": {
    "widgets": {
        "type": "hasMany",
        "model": "widget",
        "foreignKey": "account_id",
        "through": "widget_to_account"
    }
}

BUT THIS:

"relations": {
    "widgets": {
        "type": "hasMany",
        "model": "widget",
        "foreignKey": "account_id",
        "through": "widget_to_account",
        "keyThrough": "widget_id"
    }
}

This is not made super clear, and is even stated incorrectly in the loopback api docs. I wish they'de stop this "auto-naming" paradigm they've been pushing around. Looking at loopback SO and the wider community, it's generally caused so much pain with models being named incorrectly, keys like this being set to totally arbitary names -.-

Upvotes: 10

Related Questions