4

I'm trying to deep populate a collection.

For example

// UnitType.js
name: { type: 'string' }

// Unit.js
unitType: {
  model: 'unitType',
  via: '_id',
  required: true,
  index: true
}

// Product.js
unit: {
  model: 'unit',
  via: '_id',
  required: true,
  index: true
},

The problem is, that - as far I know from internet research deep populate like

Product.find().populate('unit.unitType');

is currently not supported in sails. To achieve the result I want I currently

  • query Products with populate unit
  • query UnitTypes with the id from `product.unit.unitType``
  • .map() product.unit.unitType with the response

This is of course far from ideal. I also tried using toJSON in the model to "pre-populate" the unitType -> doesn't work since this doesn't support Promises.

There are quite a few threads on so and PR's on github on this issue, but so far I haven't found a solution to this problem. Is there any way to make this better?

Markus
  • 1,565
  • 6
  • 26
  • 57
  • If you are using async/await or generators (probably not) in your workflow, you can use my gist (compile it to js) and merge it into your model , its just a WIP though... https://gist.github.com/Zaggen/7de61775ed083d10c07e – Lu Roman Apr 18 '16 at 15:05

1 Answers1

6

You could try to replace Waterline ORM with Offshore ORM. There is a hook for sails to do that - sails-hook-orm-offshore.

It's quite easy to implement to your existing project, because its fork of Waterline wits some more features. Only cons i found is that sails-hook-validation stopped working.

How to install

npm install sails-hook-orm-offshore --save

Configuration

.sailsrc

{
    "hooks": {
        "orm": false,
        "pubsub": false
    }
}

Defaults

config/globals.js

adapters: true,
models: true

Usage

Now you will be allowed to deep populate in your queries. For example (from documentation):

User.find()
.populate('foo.bar', { name: 'foo' }) //populate foo into user and bar into foo
.exec(function(err, users) {
    console.log(users[0].foo.bar.name) // 'foo'
});

Second option

Merge deep populate with waterline

npm i Atlantis-Software/waterline#deepPopulate
Bonanza
  • 1,601
  • 14
  • 23
  • thank you for your comment, but unfortunately it doesn't work as expected (and if messes around with the whole project, which leads to not working rest calls all over my project). I guess I'll have to stick to my current solution until sails/waterline implements deep populate – Markus Apr 18 '16 at 09:05
  • So maybe just merge deep populate with waterline yourself. Uninstall that hook from my solution and execute that: npm i Atlantis-Software/waterline#deepPopulate (that is merge request for waterline) – Bonanza Apr 18 '16 at 09:18
  • would be really nice, but the error (timeout) is still the same – Markus Apr 18 '16 at 09:59
  • Timeout while getting the data? Have you tried to execute model method from node cli? Maybe you are trying to get too much data at once. – Bonanza Apr 18 '16 at 10:01
  • my bad with the timeout, the actual error is `Error: Encountered unexpected error while building join instructions for .populate(\"unit.unitType\")` models are defined like I wrote above -> unit definately has a unitType – Markus Apr 18 '16 at 10:12
  • Try this: Product.find().populate('unit').populate('unit.unitType'); – Bonanza Apr 18 '16 at 10:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/109422/discussion-between-bonanza-and-markus). – Bonanza Apr 18 '16 at 10:15
  • @Bonanza Guys, It works me. But, when I write find query inside nested deep value, I get the result but it doesn't filter. User.find(). populate('userComments.metal', { where: { metal_code: 'P' }}).exec(function (err, response) { res.json(response); }); – Muthukumar Marichamy Jun 09 '16 at 11:20
  • Is it possible to filter the nested populate? Meaning Can I add a filter on foo level ? – Saroj May 30 '18 at 10:16