Added suffix support to populate() #991

Closed
wants to merge 2 commits into from

3 participants

@STRML

ExtJS and other frameworks don't play well with the populate() function in Mongoose. ExtJS expects a certain field to be populated with an association, or null if the object is not denormalized. The problem is that if I choose not to denormalize an object and send it down to ExtJS, its Model structure will attempt to treat the object ID as an actual Model and fail.

Call populate(path, fields, conditions, options) with options.suffix defined, and the populated object will go into a new field, key+suffix, instead of overwriting the key field.

For example, for compatibility with ExtJS4, we might want to send down an object in this manner to be friendly to ExtJS' association support:

User.findById("id").populate('comment', null, null, {suffix: '_obj'}).run(function(err, user){...});

Which yields:

User{
...
comment: "4f5cd5f6e9786ec113000006"
comment_obj: {text: "foo"}
...
}

ExtJS is then instructed that the associationKey is 'comment_obj'. This means it will correctly use the contents of 'comment_obj' to construct a model when it is present, but will not if it is not present.

@STRML STRML Added suffix support to populate().
Call populate(path, fields, conditions, options) with options.suffix
defined, and the populated object will go into a new field, key+suffix,
instead of overwriting the id field.

For example, for compatibility with ExtJS4, we might want to send down
an object in this manner to be friendly to ExtJS' association support:

User{
   comment: "4f5cd5f6e9786ec113000006"
   comment_obj: {text: "foo"}
}

Calling User.findOne().populate('comment', null, null, {suffix:
'_obj'}) will add this suffix.
e0fe98a
@defunctzombie

-1 for adding extjs specific functionality. I would think that the extjs side should be responsible for being able to setup associations on their end? Or just denormalize it yourself before sending.

@STRML

This is not strictly ExtJS specific, there are many reasons to want to denormalize an object into a field that is not the foreign key field. It would be nice to at least have that option.

@aheckmann

so far the only reason stated is better extjs compatibility. thats a respectable goal, are there any other use cases where this would help?

@STRML

I don't have any concrete examples as I have only used Mongoose with ExtJS, but any strongly-typed language or rigid framework receiving information from Mongoose is going to balk at the ambiguity created by populate(). Sometimes a model association key is a String, sometimes it is an Object. With a suffix, you can be sure that the association key is always a String or null, and the association key + "_obj" is always an Object or null.

@aheckmann aheckmann commented on the diff Jul 11, 2012
lib/model.js
@@ -246,14 +249,15 @@ Model.prototype.init = function init (doc, query, fn) {
} else {
self._populate(schema, obj[i], poppath, function (err, doc) {
if (err) return error(err);
- obj[i] = doc;
+ if(suffix && doc !== null) obj[i + suffix] = doc;
+ else obj[i] = doc;

please remove the null check. should be consistent regardless of prefix

@STRML
STRML added a note Jul 11, 2012

The reason the null check is here is so that it will make obj[i]=null if the doc is null. Not sure what the desired behavior would be in this situation. If I remove the null check obj[i+suffix]=null but obj[i] still contains the id.

In a sense the null check makes it consistent because the id is eliminated if it isn't valid, regardless of whether or not you've set a suffix.

the id isn't necessarily invalid. the user may have passed conditions to filter out data.

if there's a suffix just use it and leave the original alone. please add tests for both singe property population and population of arrays.

@STRML
STRML added a note Jul 25, 2012

Good point. Okay, I will add those.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@aheckmann aheckmann commented on the diff Jul 11, 2012
lib/model.js
@@ -234,7 +236,8 @@ Model.prototype.init = function init (doc, query, fn) {
self._populate(schema.schema.path(key), subobj[key], poppath.sub[key], done);
function done (err, doc) {
if (err) return error(err);
- subobj[key] = doc;
+ if(suffix && doc !== null) subobj[key + suffix] = doc;

please remove the null check. should be consistent regardless of prefix

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

ok I'm down. I added some comments

@aheckmann aheckmann closed this Feb 15, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment