Skip to content

Instantly share code, notes, and snippets.

@dinana
Last active June 13, 2019 08:33
  • Star 16 You must be signed in to star a gist
  • Fork 6 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save dinana/52453ecb00d469bb7f12 to your computer and use it in GitHub Desktop.
Util Sails Service with PopulateDeep function
User.find(id).populate('preferences').exec(function (err, user) {
if(err) {
sails.log.error("ERR:", err);
}
sails.services['util'].populateDeep('user', user[0], 'preferences.nestedPreferences', function (err, newUser) {
if (err) {
sails.log.error("ERR:", err);
}
console.log(newUser);
});
});
/**
* Created by dinana on 25/4/15.
* Please keep credits for re-use.
*/
function populateDeep2(parentModelName, parentModel, path, cb) {
if( !path || path.length == 0 ) {
cb("No path given");
return;
}
var count = 0;
var parent = JSON.parse(JSON.stringify(parentModel));
populateDeepInner(parentModelName, parent, path, cb);
function populateDeepInner(parentModelName, parentInstance, path, cb) {
if(Array.isArray(parentInstance)) {
count = count + parentInstance.length;
parentInstance.map(function(value, index, origArray){
handle(value)
})
} else {
count++;
handle(parentInstance)
}
function handle(parentInstance) {
var pathArray = path.split('.');
var childInstance = parentInstance[pathArray[0]]
if (isPopulated(childInstance)) {
doneIfDone(childInstance, pathArray);
} else {
var childAssociation = getChildModel(parentModelName, pathArray[0]);
var findCriteria;
switch (childAssociation.type) {
case 'model':
findCriteria = childInstance;
break;
case 'collection':
findCriteria = {};
findCriteria[childAssociation.via] = parentInstance.id;
break;
}
if(pathArray.length > 1) {
childAssociation.model.find(findCriteria)
.populate(pathArray[1]).exec(function (err, populatedChild) {
if(err) {
console.log("Error:",err)
cb(err)
}
// pathArray.splice(0,1)
stitcher(populatedChild);
})
} else {
childAssociation.model.find(findCriteria)
.exec(function (err, populatedChild) {
if(err) {
console.log("Error:",err)
cb(err)
}
// pathArray.splice(0,1)
stitcher(populatedChild);
})
}
}
function stitcher(newChildInstance) {
newChildInstance = JSON.parse(JSON.stringify(newChildInstance));
switch(getChildModel(parentModelName,pathArray[0]).type) {
case 'model':
parentInstance[pathArray[0]] = newChildInstance[0];
break;
case 'collection':
parentInstance[pathArray[0]] = newChildInstance;
break;
}
doneIfDone(newChildInstance)
}
// Assumptions: newChild is already populated
function doneIfDone(newChildInstance) {
if(pathArray.length > 1) {
var newPathArray = pathArray.slice(1)
var newPath = newPathArray.join('.');
count--;
populateDeepInner(getChildModel(parentModelName, pathArray[0]).modelName, newChildInstance, newPath, cb);
} else {
count--;
if (count == 0)
cb(null, parent);
}
}
function getChildModel(parentModelName, childModelName) {
var childAssociation = sails.models[parentModelName.toLowerCase()].associations.filter(function (value) {
return value.alias == childModelName;
})
return {model:sails.models[childAssociation[0][childAssociation[0].type]], type:childAssociation[0].type, via: childAssociation[0].via, modelName:childAssociation[0][childAssociation[0].type]};
}
}
function isPopulated(model) {
return (model && typeof model != 'string')
}
}
}
module.exports = {populateDeep:populateDeep2}
@Tenkir
Copy link

Tenkir commented Apr 29, 2015

You have a typo on line 91.

It should be

return value.alias = childModelName;

@albertkim
Copy link

I can't quite get this to work (the nested populate doesn't occur, and only the first populate is returned). Are there certain conditions under which this service function will not run?

When I try a double-nested populate, I receive the following error:

C:\Users\*\Documents\GitHub\*\api\services\NestedPopulateService.js:93
  return {model:sails.models[childAssociation[0][childAssociation[0].type]], t
                                                                    ^
TypeError: Cannot read property 'type' of undefined
    at getChildModel (C:\Users\*\Documents\GitHub\*\api\services\NestedPopulateService.js:93:83)

Line 93 is the following:

return {model:sails.models[childAssociation[0][childAssociation[0].type]], type:childAssociation[0].type, via: childAssociation[0].via, modelName:childAssociation[0][childAssociation[0].type]};

This is such an in-demand function, I think a few lines of comments/examples would help out a lot.

@khalilTN
Copy link

Could you please post your Models ? Thanks !

@Anandapriyan
Copy link

Hi , @dinana This is awesome since we have it in service we can reuse it in all controller. Thanks for the great work.

One Doubt say that we have more than one path i.e, like preferences.nestedPreferences1 or preferences1.nestedPreferences with the above model how can we pass the query

Thanks

@Tenkir
Copy link

Tenkir commented Aug 2, 2015

This has stopped working for me. Any idea why?

Edit: seems like this only works with mongoDB.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment