Skip to content

mongoose plugin for tree hierarchy using the materialized path strategy

Notifications You must be signed in to change notification settings

Spown/mongoose-path-tree

 
 

Repository files navigation

mongoose-path-tree

Build Status

Code Climate Test Coverage Issue Count

Dependency Status devDependency Status

Implements the materialized path strategy with cascade child re-parenting on delete for storing a hierarchy of documents with mongoose Version with all collected features and fixes from mongoose-tree, mongoose-tree-fix, mongoose-tree2, mongoose-reparenting-tree

Usage

Install via NPM

$ npm install mongoose-path-tree

Options

Model.plugin(tree, {
  pathSeparator : '#',              // Path separator. Default: '#'
  onDelete :      'REPARENT',       // Can be set to 'DELETE' or 'REPARENT'. Default: 'DELETE'
  numWorkers:     5,                // Number of stream workers. Default: 5
  idType:         Schema.ObjectId   // Type used for _id. Default: This Model Schema's _id type
  treeOrdering: false || 'position_field_name' // adds a "position" field for siblings on the same level to be moved and swapped
})

Then you can use the plugin on your schemas

var tree = require('mongoose-path-tree');

var UserSchema = new Schema({
  name : String
});
UserSchema.plugin(tree);
var User = mongoose.model('User', UserSchema);

var adam = new User({ name : 'Adam' });
var bob = new User({ name : 'Bob' });
var carol = new User({ name : 'Carol' });

// Set the parent relationships
bob.parent = adam;
carol.parent = bob;

adam.save(function() {
  bob.save(function() {
    carol.save();
  });
});

At this point in mongoDB you will have documents similar to

    {
      "_id" : ObjectId("50136e40c78c4b9403000001"),
      "name" : "Adam",
      "path" : "50136e40c78c4b9403000001"
    }
    {
      "_id" : ObjectId("50136e40c78c4b9403000002"),
      "name" : "Bob",
      "parent" : ObjectId("50136e40c78c4b9403000001"),
      "path" : "50136e40c78c4b9403000001#50136e40c78c4b9403000002"
    }
    {
      "_id" : ObjectId("50136e40c78c4b9403000003"),
      "name" : "Carol",
      "parent" : ObjectId("50136e40c78c4b9403000002"),
      "path" : "50136e40c78c4b9403000001#50136e40c78c4b9403000002#50136e40c78c4b9403000003"
    }

The path is used for recursive methods and is kept up to date by the plugin if the parent is changed

API

getChildren

Signature:

doc.getChildren([filters], [fields], [options], [recursive], cb);

args are additional filters if needed. if recursive is supplied and true, subchildren are returned

Based on the above hierarchy:

adam.getChildren(function(err, users) {
  // users is an array of with the bob document
});

adam.getChildren(true, function(err, users) {
  // users is an array with both bob and carol documents
});

getChildrenTree

Signature as a method:

doc.getChildrenTree([args], cb);

Signature as a static:

Model.getChildrenTree([rootDoc], [args], cb);

returns (Object): recursive tree of sub-children.

args is an object you can defined with theses properties :

  • filters: Object, mongoose query filter, optional, default: {}
  • fields: String|Object, mongoose fields, optional, default: null (all fields)
  • options: Object, mongoose query option, optional, default: {}
  • minLevel: Number, level at which will start the search, default: 1
  • recursive: Boolean, make the search recursive or only fetch children for the specified level, default: true
  • allowEmptyChildren: Boolean, if true, every child not having children would still have children attribute (an empty array), if false, every child not having children will have children attribute at all, default: true
  • objectify: Boolean|Object, wheather to run toObject() method on every child, can be either Boolean or an toObject() options Object, default: false
  • populationQuery: String, populate fields, default: ''

Example :

var args = {
  filters: {owner:myId},
  fields: "_id name owner",
  minLevel:2,
  recursive:true,
  allowEmptyChildren:false
}

getChildrenTree(args,myCallback);

Based on the above hierarchy:

adam.getChildrenTree( function(err, users) {

    /* if you dump users, you will have something like this :
    {
      "_id" : ObjectId("50136e40c78c4b9403000001"),
      "name" : "Adam",
      "path" : "50136e40c78c4b9403000001"
      "children" : [{
          "_id" : ObjectId("50136e40c78c4b9403000002"),
          "name" : "Bob",
          "parent" : ObjectId("50136e40c78c4b9403000001"),
          "path" : "50136e40c78c4b9403000001#50136e40c78c4b9403000002"
          "children" : [{
              "_id" : ObjectId("50136e40c78c4b9403000003"),
              "name" : "Carol",
              "parent" : ObjectId("50136e40c78c4b9403000002"),
              "path" : "50136e40c78c4b9403000001#50136e40c78c4b9403000002#50136e40c78c4b9403000003"
          }]
      }]
    }
    */

});

getAncestors

Signature:

doc.getAncestors([filters], [fields], [options], cb);

Based on the above hierarchy:

carol.getAncestors(function(err, users) {
  // users as an array [adam, bob] (older -> younger)
})

getSiblingsAndSelf

alias: siblingsAndSelf

doc.getSiblingsAndSelf(function(err, docs) {
  
});

Returns this document's siblings and itself in an array

getSiblings

alias: siblings

doc.getSiblings(function(err, docs) {
  
});

Returns this document's siblings in an array

moveToPosition

doc.moveToPosition(positin, function(err, docs) {
  
});

Move this node to the specified position (number, zero-based) on the same level and swaps it with the other doc (also changes the target doc's position field value)

level

Virtual property (Number, strating at 1), equals to the level in the hierarchy

carol.level; // equals 3

Tests

To run the tests install mocha

npm install mocha -g

and then run

mocha

About

mongoose plugin for tree hierarchy using the materialized path strategy

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%