Skip to content

Commit

Permalink
updating findChildrenId to use distinct instead of stream.
Browse files Browse the repository at this point in the history
  • Loading branch information
mariuskubilius committed May 2, 2013
1 parent 4f7a6f5 commit bc8b177
Showing 1 changed file with 149 additions and 160 deletions.
309 changes: 149 additions & 160 deletions lib/ancestorTree.js
Expand Up @@ -10,171 +10,160 @@ var ObjectId = Mongoose.Schema.ObjectId;


ancestorTree = function(schema){ ancestorTree = function(schema){


var fields = {}; var fields = {};
if (!schema.paths.parent) { if (!schema.paths.parent) {
fields.parent = { fields.parent = {
type: ObjectId, type: ObjectId,
set : function(val) { set : function(val) {
if(typeof(val) === "object" && val._id) { if(typeof(val) === "object" && val._id) {
return val._id; return val._id;
} }
if(val === '') { return undefined} if(val === '') { return undefined}
return val; return val;
}, },
index: true index: true
} }
} }
if (!schema.paths.ancestors) { if (!schema.paths.ancestors) {
fields.ancestors = [{type: ObjectId, index: true}]; fields.ancestors = [{type: ObjectId, index: true}];
} }
schema.add(fields); schema.add(fields);
var createAncestors = function(ancestors, parent) { var createAncestors = function(ancestors, parent) {
return ancestors.push(parent); return ancestors.push(parent);
} }
schema.pre('save', function (next) { schema.pre('save', function (next) {
var parentModified = this.isDirectModified('parent'); var parentModified = this.isDirectModified('parent');
var self = this; var self = this;
if (self.isNew || parentModified) { if (self.isNew || parentModified) {
if(!self.parent && self.isNew){ if(!self.parent && self.isNew){
return next(); return next();
} }
self.collection.findOne({ _id : self.parent }, function(err, doc) { self.collection.findOne({ _id : self.parent }, function(err, doc) {
if(err) return next(err); if(err) return next(err);
var oldAncestorsLength = self.ancestors.length; var oldAncestorsLength = self.ancestors.length;
if(doc) { if(doc) {
self.ancestors = doc.ancestors; self.ancestors = doc.ancestors;
// @todo find atomic operation for that. // @todo find atomic operation for that.
self.ancestors.nonAtomicPush(self.parent); self.ancestors.nonAtomicPush(self.parent);
//self.markModified('ancestors'); //self.markModified('ancestors');
} }
else { else {
self.ancestors = []; self.ancestors = [];
self.markModified('ancestors'); self.markModified('ancestors');
} }
if(!self.isNew && parentModified){ if(!self.isNew && parentModified){
self.collection.find({ ancestors : self._id }, function(err, cursor) { self.collection.find({ ancestors : self._id }, function(err, cursor) {
if(err) return next(err); if(err) return next(err);
var stream = cursor.stream(); var stream = cursor.stream();
stream.on('data', function (doc) { stream.on('data', function (doc) {
//console.log(self.ancestors.concat(doc.ancestors.slice(oldAncestorsLength))); //console.log(self.ancestors.concat(doc.ancestors.slice(oldAncestorsLength)));
var newPath = self.ancestors.concat(doc.ancestors.slice(oldAncestorsLength)); var newPath = self.ancestors.concat(doc.ancestors.slice(oldAncestorsLength));
self.collection.update({ _id : doc._id }, { $set : { ancestors : newPath } }, function(err){ self.collection.update({ _id : doc._id }, { $set : { ancestors : newPath } }, function(err){
if(err) return next(); if(err) return next();
}); });
}); });
stream.on('close', function() { stream.on('close', function() {
next(); next();
}); });
stream.on('error', function(err) { stream.on('error', function(err) {
next(err); next(err);
}); });
}); });
} }
else{ else{
next(); next();
} }
}); });
} }
else{ else{
next(); next();
} }
}); });
schema.pre('remove', function(next){ schema.pre('remove', function(next){
this.collection.count({ancestors: this._id},function(err, count){ this.collection.count({ancestors: this._id},function(err, count){
if(err) return next(err); if(err) return next(err);
if(count > 0 ){ if(count > 0 ){
return next(new Error('Please delete/move all children before proceeding')); return next(new Error('Please delete/move all children before proceeding'));
} }
else { else {
return next(); return next();
} }
}); });
}); });
schema.method('findDirectChildren', function(opts, cb) { schema.method('findDirectChildren', function(opts, cb) {
if(arguments.length === 1 && typeof arguments[0] === 'function'){ if(arguments.length === 1 && typeof arguments[0] === 'function'){
cb = opts; cb = opts;
opts = {}; opts = {};
} }
opts = opts || {}; opts = opts || {};
fields = opts.fields || {title: 1, slug: 1}; fields = opts.fields || {title: 1, slug: 1};
return this.model(this.constructor.modelName).find({parent: this._id}, fields, cb); return this.model(this.constructor.modelName).find({parent: this._id}, fields, cb);
}); });


schema.method('findChildren', function(opts, cb) { schema.method('findChildren', function(opts, cb) {
if(arguments.length === 1 && typeof arguments[0] === 'function'){ if(arguments.length === 1 && typeof arguments[0] === 'function'){
cb = opts; cb = opts;
opts = {}; opts = {};
} }
opts = opts || {}; opts = opts || {};
fields = opts.fields || {title: 1, slug: 1}; fields = opts.fields || {title: 1, slug: 1};
return this.model(this.constructor.modelName).find({ancestors: this._id}, fields, cb); return this.model(this.constructor.modelName).find({ancestors: this._id}, fields, cb);
}); });


schema.method('getAncestors', function(opts, cb) { schema.method('getAncestors', function(opts, cb) {
if(arguments.length === 1 && typeof arguments[0] === 'function'){ if(arguments.length === 1 && typeof arguments[0] === 'function'){
cb = opts; cb = opts;
opts = {}; opts = {};
} }
opts = opts || {}; opts = opts || {};
fields = opts.fields || {title: 1, slug: 1}; fields = opts.fields || {title: 1, slug: 1};
return this.model(this.constructor.modelName).find({_id: {$in: this.ancestors}}, fields, cb); return this.model(this.constructor.modelName).find({_id: {$in: this.ancestors}}, fields, cb);
}); });
/** /**
* Static Methods for schema * Static Methods for schema
*/ */
schema.statics = { schema.statics = {


/** /**
* Find direct children * Find direct children
* @param {ObjectId} [id] _id of parent item, or null if no parent exists. * @param {ObjectId} [id] _id of parent item, or null if no parent exists.
* @param {Object} [options] pass options here * @param {Object} [options] pass options here
* @param {Function} [cb] Callback function. * @param {Function} [cb] Callback function.
*/ */
directChildren: function (parent, options, cb) { directChildren: function (parent, options, cb) {
if(arguments.length === 2 && typeof arguments[1] === 'function'){ if(arguments.length === 2 && typeof arguments[1] === 'function'){
cb = options; cb = options;
options = {}; options = {};
} }
options.fields = options.fields || {'title':1, 'slug':1}; options.fields = options.fields || {'title':1, 'slug':1};
options.sort = options.sort || {'title': 1}; options.sort = options.sort || {'title': 1};
this.find({parent: parent}) this.find({parent: parent})
.sort(options.sort) .sort(options.sort)
.select(options.fields) .select(options.fields)
.exec(cb) .exec(cb)
}, },

/**
* Find all children _ids and return them as an array
* @param {ObjectId} [current] items _id which children you are looking.
*/
childrenIdArray: function (current, cb) {
var nodes = [current];
this.find({ancestors: current}).distinct('_id', cb(err, result))
}
}


/**
* Find all children _ids and return them as an array
* @param {ObjectId} [current] items _id which children you are looking.
*/
childrenIdArray: function (current, cb) {
var nodes = [current];
this.find({ancestors: current})
.select('_id')
.stream()
.on('data', function(doc){
nodes.push(doc._id)
})
.on('error', function(err){
cb(err, nodes);
})
.on('close', function() {
cb(null, nodes)
});
}
}



}; };
/** /**
* @todo write tests for statics. * @todo write tests for statics.
Expand Down

0 comments on commit bc8b177

Please sign in to comment.