Skip to content

Commit

Permalink
populate; record populated paths from query builder
Browse files Browse the repository at this point in the history
  • Loading branch information
aheckmann committed Feb 2, 2013
1 parent c4d8139 commit a8f6554
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 20 deletions.
19 changes: 13 additions & 6 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -268,19 +268,26 @@ Document.prototype.populate = function populate () {
* @api private
*/

Document.prototype.init = function (doc, query, fn) {
// backwards compat. remove in 4.x
if ('function' == typeof query) {
fn = query;
query = null;
Document.prototype.init = function (doc, opts, fn) {
if ('function' == typeof opts) {
fn = opts;
opts = null;
}
// end backwards compat

this.isNew = false;

init(this, doc, this._doc);
this._storeShard();

// handle docs with populated paths
if (opts && opts.populated && opts.populated.length) {
var id = this.id;
for (var i = 0; i < opts.populated.length; ++i) {
var item = opts.populated[i];
this.populated(item.path, item._docs[id]);
}
}

this.emit('init', this);
if (fn) fn(null);
return this;
Expand Down
1 change: 1 addition & 0 deletions lib/internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ function InternalCache () {
this.getters = {};
this._id = undefined;
this.populate = undefined;
this.populated = undefined;
this.scope = undefined;
this.activePaths = new ActiveRoster;
}
4 changes: 4 additions & 0 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -1636,6 +1636,10 @@ function populate (model, docs, options, cb) {
ret = utils.getValue(path, doc);
}

options._docs[doc._id] = Array.isArray(ret)
? ret.slice()
: ret;

if (isDocument) {
// cache original populated _ids
doc.populated(path, Array.isArray(ret) ? ret.slice() : ret);
Expand Down
35 changes: 24 additions & 11 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ Query.prototype.setOptions = function (options, overwrite) {
// overwrite is internal use only
if (overwrite) {
options = this.options = options || {};
this.safe = options.safe
this.safe = options.safe;
if ('populate' in options) {
this.populate(this.options.populate);
}
return this;
}

Expand Down Expand Up @@ -89,6 +92,7 @@ Query.prototype.setOptions = function (options, overwrite) {
this.options[method] = options[method];
}
}

return this;
}

Expand Down Expand Up @@ -1523,15 +1527,15 @@ Query.prototype.execFind = function (callback) {
if (!self.options.populate) {
return true === options.lean
? promise.complete(docs)
: completeMany(model, docs, fields, self, promise);
: completeMany(model, docs, fields, self, null, promise);
}

var pop = utils.object.vals(self.options.populate);
model.populate(docs, pop, function (err, docs) {
if (err) return promise.error(err);
return true === options.lean
? promise.complete(docs)
: completeMany(model, docs, fields, self, promise);
: completeMany(model, docs, fields, self, pop, promise);
});
}

Expand All @@ -1545,18 +1549,22 @@ Query.prototype.execFind = function (callback) {
* @param {Array} docs
* @param {Object} fields
* @param {Query} self
* @param {Array} [pop] array of paths used in population
* @param {Promise} promise
*/

function completeMany (model, docs, fields, self, promise) {
function completeMany (model, docs, fields, self, pop, promise) {
var arr = [];
var count = docs.length;
var len = count;
var i = 0;
var opts = pop ?
{ populated: pop }
: undefined;

for (; i < len; ++i) {
arr[i] = new model(undefined, fields, true);
arr[i].init(docs[i], function (err) {
arr[i].init(docs[i], opts, function (err) {
if (err) return promise.error(err);
--count || promise.complete(arr);
});
Expand Down Expand Up @@ -1618,15 +1626,15 @@ Query.prototype.findOne = function (callback) {
if (!self.options.populate) {
return true === options.lean
? promise.complete(doc)
: completeOne(model, doc, fields, self, promise);
: completeOne(model, doc, fields, self, null, promise);
}

var pop = utils.object.vals(self.options.populate);
model.populate(doc, pop, function (err, doc) {
if (err) return promise.error(err);
return true === options.lean
? promise.complete(doc)
: completeOne(model, doc, fields, self, promise);
: completeOne(model, doc, fields, self, pop, promise);
})
}));

Expand All @@ -1640,12 +1648,17 @@ Query.prototype.findOne = function (callback) {
* @param {Document} doc
* @param {Object} fields
* @param {Query} self
* @param {Array} [pop] array of paths used in population
* @param {Promise} promise
*/

function completeOne (model, doc, fields, self, promise) {
function completeOne (model, doc, fields, self, pop, promise) {
var opts = pop ?
{ populated: pop }
: undefined;

var casted = new model(undefined, fields, true);
casted.init(doc, function (err) {
casted.init(doc, opts, function (err) {
if (err) return promise.error(err);
promise.complete(casted);
});
Expand Down Expand Up @@ -2274,7 +2287,7 @@ Query.prototype._findAndModify = function (type, callback) {
}

var casted = new model(undefined, fields, true);
casted.init(doc, self, function (err) {
casted.init(doc, function (err) {
if (err) return promise.error(err);
promise.complete(casted);
});
Expand Down Expand Up @@ -2323,7 +2336,7 @@ Query.prototype.populate = function populate () {
var res = utils.populate.apply(null, arguments);
var opts = this.options;

if (!opts.populate) {
if (!utils.isObject(opts.populate)) {
opts.populate = {};
}

Expand Down
2 changes: 1 addition & 1 deletion lib/querystream.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ QueryStream.prototype._onNextObject = function _onNextObject (err, doc) {
var instance = new this.query.model(undefined, this._fields, true);

var self = this;
instance.init(doc, this.query, function (err) {
instance.init(doc, function (err) {
if (err) return self.destroy(err);
self.emit('data', instance);

Expand Down
1 change: 1 addition & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ function PopulateOptions (path, select, match, options, model) {
this.select = select;
this.options = options;
this.model = model;
this._docs = {};
}

// make it compatible with utils.clone
Expand Down
85 changes: 84 additions & 1 deletion test/model.populate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ mongoose.model('RefAlternateUser', User);
* Tests.
*/

describe('model: ref:', function(){
describe('model: populate:', function(){
it('populating a single ref', function(done){
var db = start()
, BlogPost = db.model('RefBlogPost', posts)
Expand Down Expand Up @@ -1840,6 +1840,7 @@ describe('model: ref:', function(){
});
})
})

})

describe('populating combined with lean (gh-1260)', function(){
Expand Down Expand Up @@ -1923,4 +1924,86 @@ describe('model: ref:', function(){
});
})
})

describe('records paths and _ids used in population', function(){
var db;
var B;
var U;
var u1, u2;
var b1, b2

before(function(done){
db = start()
B = db.model('RefBlogPost', posts + random())
U = db.model('RefUser', users + random());

U.create({
name : 'Fan 1'
, email : 'fan1@learnboost.com'
}, {
name : 'Fan 2'
, email : 'fan2@learnboost.com'
}, function (err, fan1, fan2) {
assert.ifError(err);
u1 = fan1;
u2 = fan2;

B.create({
title : 'Woot'
, fans : [fan1, fan2]
, _creator: fan1
}, {
title : 'Woot2'
, fans : [fan2, fan1]
, _creator: fan2
}, function (err, post1, post2) {
assert.ifError(err);
b1 = post1;
b2 = post2;
done();
});
});
})

after(function(){
db.close()
})

it('with findOne', function(done){
B.findById(b1).populate('fans _creator').exec(function (err, doc) {
assert.ifError(err);
assert.ok(Array.isArray(doc.populated('fans')));
assert.equal(2, doc.populated('fans').length);
assert.equal(doc.populated('fans')[0], String(u1._id));
assert.equal(doc.populated('fans')[1], String(u2._id));
assert.equal(doc.populated('_creator'), String(u1._id));
done();
})
})

it('with find', function(done){
B.find().populate('fans _creator').exec(function (err, docs) {
assert.ifError(err);
assert.equal(2, docs.length);

var doc1 = docs[0];
var doc2 = docs[1];

assert.ok(Array.isArray(doc1.populated('fans')));
assert.equal(2, doc1.populated('fans').length);
assert.equal(doc1.populated('fans')[0], String(u1._id));
assert.equal(doc1.populated('fans')[1], String(u2._id));
assert.equal(doc1.populated('_creator'), String(u1._id));

assert.ok(Array.isArray(doc2.populated('fans')));
assert.equal(2, doc2.populated('fans').length);
assert.equal(doc2.populated('fans')[0], String(u2._id));
assert.equal(doc2.populated('fans')[1], String(u1._id));
assert.equal(doc2.populated('_creator'), String(u2._id));
done();
})
})
})


});
5 changes: 4 additions & 1 deletion test/query.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ describe('Query', function(){
, select: undefined
, model: undefined
, options: undefined
, _docs: {}
}
q.populate(o);
assert.deepEqual(o, q.options.populate['yellow.brick']);
Expand All @@ -746,6 +747,7 @@ describe('Query', function(){
, select: undefined
, model: undefined
, options: undefined
, _docs: {}
}
q.populate(o);
assert.equal(1, Object.keys(q.options.populate).length);
Expand All @@ -766,6 +768,7 @@ describe('Query', function(){
, select: undefined
, model: undefined
, options: undefined
, _docs: {}
}
assert.equal(2, Object.keys(q.options.populate).length);
assert.deepEqual(o, q.options.populate['yellow.brick']);
Expand Down Expand Up @@ -1258,7 +1261,7 @@ describe('Query', function(){
q.setOptions({ read: ['s', [{dc:'eu'}]]});

assert.equal(q.options.thing, 'cat');
assert.deepEqual(q.options.populate.fans, { path: 'fans', select: undefined, match: undefined, options: undefined, model: undefined });
assert.deepEqual(q.options.populate.fans, { path: 'fans', select: undefined, match: undefined, options: undefined, model: undefined, _docs: {} });
assert.equal(q.options.batchSize, 10);
assert.equal(q.options.limit, 4);
assert.equal(q.options.skip, 3);
Expand Down

0 comments on commit a8f6554

Please sign in to comment.