Search code examples
feathersjs

Custom result with feathers


I have been making an API server with feathers. I have two mongoose services. Now my requirement is I want one API that has a result of both services. Let's say product-master and product are two services. The output I want is to merge both services.

To accomplish this I found one way is hook. So I tried this.

module.exports = function () {
return function (hook) {
let Product = hook.app.service('product').Model;

return new Promise(function(resolve, reject){
  Product.find({}, function(err, products) {
    var productMap = [];
    products.forEach(function(product) {
      productMap.push(products);
    });
    res.send(productMap);
    console.log(productMap);
    resolve(hook);
  });
});
};
};

Now I called the hook on before find method of product-master But I don't understand how to merge the records of product to product-master service.

And one more thing is how to create a one different API that has a merged result and custom route like http://localhost:3030/products.

Update

I found one post on stackoverflow, this might be helpful.


Solution

  • There are different ways for what I think you want to do. I also recommend not using the models directly but the services you want (by calling their service methods). You also want to be familiar with the API for hooks. Then you have some options:

    1) Modifying the existing results

    To modify the result of an existing service call, modify hook.result in an after hook:

    module.exports = function () {
      return function (hook) {
        let productService = hook.app.service('product');
    
        return productService.find({
          paginate: false // Turn off pagination
        }).then(products => {
          hook.result.products = products;
          return hook;
        });
      };
    };
    

    Then

    const myHook = require('../../hooks/myhook');
    
    app.service('products-master').hooks({
      after: {
        get: [ myHook() ]
      }
    });
    

    This will add a products property when getting a single item from the products-master service.

    2) Setting hook.result

    To skip a database call you can set hook.result to what you want to return in a before hook. Keep in mind that all after hooks will still run.

    3) Using a custom service

    In a custom service you can do whatever you like, for example get all the things you need and put them together manually:

    app.use('/all-products', {
      find() {
        return this.app.service('products-master').find(params).then(page => {
          const promises = page.data.map(masterProduct => {
            return this.app.service('products').find({
              paginate: false,
              query: {
                masterProductId: masterProduct._id
              }
            }).then(products => {
              // Add to masterProduct
              masterProduct.products = products;
            });
          });
    
          return Promise.all(promises).then(() => {
            // Return `page` which has the modified data
            return page;
          });
        });
      },
    
      setup(app) {
        this.app = app;
      }
    });
    

    In the generator a custom service can be created by choosing custom service and modifying the servicename.class.js.

    4) The populate hook

    Since I think you just want to populate related entities you can also have a look at the populate common hook. It can do those things automatically.

    5) Using Mongoose $populate

    The Mongoose Feathers adapter also supports the $populate query parameter which allows you to pull in relationships that you defined in your Mongoose model.

    For more information on associations in Feathers also see this FAQ.