strongloop / loopback

LoopBack makes it easy to build modern applications that require complex integrations.

Home Page:http://loopback.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Scopes in model relations - strongloop api

j0n47h4n opened this issue · comments

commented

I found in the documentation that scopes enable you to specify commonly-used queries that you can reference as method calls on a model. Below i have a category model. I am trying to create scopes that apply to the relation. Unfortunately the below does nothing. How can I get scopes to apply to relation as shown below?

GET /Categories/{id}/games - This gets all games

I tried to modify the model: common/models/category.json

"relations": {
    "categories": {
      "type": "hasMany",
      "model": "Categories",
      "foreignKey": "",
      "scopes": {
        "mature": {"where": {"mature": true}},
        "sports": {"where": {"sports": true}},
      }
    }
},

I want to be able to get the data through endpoing: /Categories/{id}/games/mature

Table schema:

catgories

category_name       category_id 
-------------       -----------
fighting            1001
racing              1002
sports              1003

games

game_name           category_id     mature
------------        -----------     --------------
Tekken              10001           true
Forza               10002           false
commented

hey @j0n47h4n Do you have to use categories/{id}/games/mature as the endpoint?
If not, according to your description, I uploaded my solution to sandbox.

I think first you need to create a hasMany relation from category to game, not from category to itself (maybe it's a typo in your code? :) ). And don't forget to establish belongsTo relation from game to category as well.

In file /server/boot/sample.js I showed how to create the instances and query, in my solution,
you can either use

 Game.find({
        "where": {
            categoryId: 1,
            mature: true
        }
       }, function(err, result) {
         //TODO
       }
}

in .js code
or
use endpoint
/api/categories/1/games?filter[where][mature]=true
in browser to get the result.
Does my solution help? Let's solve it together if you have any further questions, thanks!

commented

Hey @jannyHou, thanks for your assistance. You are right it was typo there is a hasMany relation from category to game. Ok I tried your solution but Yes, I am looking to use categories/{id}/games/mature as the endpoint. I really dont want to expose the query in the end point like /api/categories/1/games?filter[where][mature]=true

commented

@jannyHou Any thoughts/ideas how to implement end point categories/{id}/games/mature?

commented

hey @j0n47h4n we don’t expose the 2nd level (related) scope over REST right now, so your expected endpoint is not supported yet. But we will mark it as a feature, and thank for your suggestion!

commented

@jannyHou hmm there are 156 open issues with the features tag and 24 closed. So I am guessing that it will be a long while before that gets implemented.

@j0n47h4n There are probably more open issues than that! ;p More like 500+ issues. Anyways, we get around to issues whenever we have time. If you need priority support, see https://strongloop.com/node-js/subscription-plans/ for subscription plan pricing. In addition, feel free to send us a message at callback@strongloop.com with your specific needs and they can answer any other questions you may have there.

So you want to list every category containing at least one game rated as mature?

Or is it, for each of the above, include matching games?

commented

Hi @amenadiel, List all games under a certain category that are mature. For Example, I want to get all the games rated mature for games under category fighting, Endpoint would be categories/1001/games/mature

In that case I'd add a remote method to game.js

     Game.mature = function(id_category, cb) {
         Game.find({
              "where": {
                  categoryId: id_category,
                  mature: true
              }
         }, function(err, results) {
             cb(err, results);
         });
     };

     Game.remoteMethod('mature', {
         accepts: [{
             arg: 'id_category',
             type: 'number'
         }],
         returns: {
             arg: 'data',
             type: 'object',
             root: true
         },
         http: {
             path: '/mature/:id_category',
             verb: 'get'
         },
         description: 'Lists mature games for a given category'
     });

So the endpoint would be /games/mature/{{id_category}}'

commented

Thanks @amenadiel close to what I want but not quite. For anyone trying to achieve the same goal, currently it can only be done using Remote Methods as mentioned above.

Added the remote methods to common/models/category.js

module.exports = function(Category) {

    Category.mature = function(id, callback) {
        var app = this.app;
        var Game = app.models.Game;
        Game.find({
            "where": {
                categoryId: id,
                mature: true
            }
        }, function(err, gameArr) {
            if (err) return callback(err);
            console.log(gameArr);
            callback(null, gameArr);
        });
    }

    Category.remoteMethod(
        'mature', {
            accepts: [{
                arg: 'id',
                type: 'number',
                required: true
            }],
            // mixing ':id' into the rest url allows $owner to be determined and used for access control
            http: {
                path: '/:id/games/mature',
                verb: 'get'
            },
            returns: {
                arg: 'games',
                type: 'array'
            }
        }
    );

};

Add the ACL property common/models/category.json.

.....
.....
"acls": [
  {
     "principalType": "ROLE",
     "principalId": "$everyone",
     "permission": "ALLOW",
     "property": "mature"
  }
] 

Now I am able to get all games that are mature by get method: http://0.0.0.0:3000/api/categories/:id/games/mature

Hey @j0n47h4n

In your example you access Game model within the category.js by doing:

module.exports = function(Category) {

    Category.mature = function(id, callback) {
        var app = this.app;
        var Game = app.models.Game;
        .
        .
        .
     }
}

However when I try to do the same thing receive the following error:

TypeError: Cannot read property 'app' of undefined
So my question is: what is the right way to access to a model (in this case Game) within another model's (in this case Category ) .js file?

UPDATE:
Found the answer to my question here: #1213

commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

commented

This issue has been closed due to continued inactivity. Thank you for your understanding. If you believe this to be in error, please contact one of the code owners, listed in the CODEOWNERS file at the top-level of this repository.