sails.js Blueprint query by relations

徘徊边缘 提交于 2020-01-02 08:19:20

问题


I'm running sails 0.10.5 with postgresql support and I want to ask if there is any way to do a query to filter results by relations. For example:

http://api/documents?user.role=Admin

Or

http://api/documents?where={"user.role": "Admin"}

Or

http://api/documents?where={"user.role": {"like": "%Admin%"}}

Where a model Document has a belongsTo relation to User which has an attribute called role (string f.e.).

I wasn't able to do such query, Am I missing something?

Thank you!


回答1:


I don't think that it's possible with SailsJS 0.10.5 for now. Actually I would like to do the same thing, so I decided to do implement a quick hack for this purpose.

Open file sails/lib/hooks/blueprints/actionUtil.js, edit method populateEach like below:

populateEach: function ( query, req ) {
    var DEFAULT_POPULATE_LIMIT = sails.config.blueprints.defaultLimit || 30;
    var _options = req.options;
    var aliasFilter = req.param('populate');
    var shouldPopulate = _options.populate;

    // Convert the string representation of the filter list to an Array. We
    // need this to provide flexibility in the request param. This way both
    // list string representations are supported:
    //   /model?populate=alias1,alias2,alias3
    //   /model?populate=[alias1,alias2,alias3]
    if (typeof aliasFilter === 'string') {
        aliasFilter = aliasFilter.replace(/\[|\]/g, '');
        aliasFilter = (aliasFilter) ? aliasFilter.split(',') : [];
    }

    return _(_options.associations).reduce(function populateEachAssociation (query, association) {        
        // If an alias filter was provided, override the blueprint config.
        if (aliasFilter) {
            shouldPopulate = _.contains(aliasFilter, association.alias);
        }

        // Only populate associations if a population filter has been supplied
        // with the request or if `populate` is set within the blueprint config.
        // Population filters will override any value stored in the config.
        //
        // Additionally, allow an object to be specified, where the key is the
        // name of the association attribute, and value is true/false
        // (true to populate, false to not)
        if (shouldPopulate) {
            // IMPORTANT NOTE: This is my trick. We should take advanced options from request parameter to make requests even more flexible
            var populationOptions = req.param('populate_' + association.alias);

            if (!populationOptions) {
                var populationLimit = _options['populate_' + association.alias+'_limit'] ||
                                      _options.populate_limit ||
                                      _options.limit ||
                                      DEFAULT_POPULATE_LIMIT;
                populationOptions = {limit: populationLimit};
            }

            return query.populate(association.alias, populationOptions);
        }
        else { 
            return query;
        }
    }, query);
},

Yay! Now your API can handle additional association filters like below:

# POST /api/documents
{
    "where" : {
        // Normal conditions
    }
    "populate_user": {
        // Advanced condition for association 'admin'
        "where" : {
            "role" : {
                 "like": "%Admin%"
            }
        },
        "limit" : 4    
     }
}

I hope that it helps. By the way I will find time to send a pull request of this improvement to SailsJS core tomorrow.

P/S: SailsJS core is quite well made. Probably core committers are just too busy to handle all feature requests. Let's contribute!




回答2:


Seems the "population" is working fine in sails v0.12. I tested it for 1st level - associations and is working fine. But still didn't get a usable and reliable method to get only dominant model records that satisfy certain criteria in deep associations -> that was the original question, or even on 2nd or 3rd level deep. Writing custom controllers is the only way for now, or overhauling the client with more logic to handle such "inverse" search, this is how im doing it for now.

First i find the associated model that satisfy the needed criteria, then from this set i'm taking out "distinct" dominant record id's. It usually means at least one or two more requests to the server / level, because the final query has "OR" array of dominant model id's.

Furthermore making POST requests to some url to actually get data isn't such a great idea because it breaks the core of REST principles: https://spring.io/understanding/REST



来源:https://stackoverflow.com/questions/27275641/sails-js-blueprint-query-by-relations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!