Module: Mongoid::Tree

Extended by:
ActiveSupport::Concern
Defined in:
lib/mongoid/tree.rb,
lib/mongoid/tree/ordering.rb,
lib/mongoid/tree/traversal.rb,
lib/mongoid/tree/rational_numbering.rb

Overview

Mongoid::Tree

This module extends any Mongoid document with tree functionality.

Usage

Simply include the module in any Mongoid document:

class Node
  include Mongoid::Document
  include Mongoid::Tree
end

Using the tree structure

Each document references many children. You can access them using the #children method.

node = Node.create
node.children.create
node.children.count # => 1

Every document references one parent (unless it’s a root document).

node = Node.create
node.parent # => nil
node.children.create
node.children.first.parent # => node

Destroying

Mongoid::Tree does not handle destroying of nodes by default. However it provides several strategies that help you to deal with children of deleted documents. You can simply add them as before_destroy callbacks.

Available strategies are:

  • :nullify_children – Sets the children’s parent_id to null

  • :move_children_to_parent – Moves the children to the current document’s parent

  • :destroy_children – Destroys all children by calling their #destroy method (invokes callbacks)

  • :delete_descendants – Deletes all descendants using a database query (doesn’t invoke callbacks)

Example:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  before_destroy :nullify_children
end

Callbacks

Mongoid::Tree offers callbacks for its rearranging process. This enables you to rebuild certain fields when the document was moved in the tree. Rearranging happens before the document is validated. This gives you a chance to validate your additional changes done in your callbacks. See ActiveModel::Callbacks and ActiveSupport::Callbacks for further details on callbacks.

Example:

class Page
  include Mongoid::Document
  include Mongoid::Tree

  after_rearrange :rebuild_path

  field :slug
  field :path

  private

  def rebuild_path
    self.path = self.ancestors_and_self.collect(&:slug).join('/')
  end
end

Defined Under Namespace

Modules: ClassMethods, Ordering, RationalNumbering, Traversal

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.after_rearrangeundefined

Note:

Generated by ActiveSupport

Sets a callback that is called after the document is rearranged

Examples:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  after_rearrange :do_something

private

  def do_something
    # ...
  end
end

Returns:

  • (undefined)


# File 'lib/mongoid/tree.rb', line 170

.before_rearrangeundefined

Note:

Generated by ActiveSupport

Sets a callback that is called before the document is rearranged

Examples:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  before_rearrage :do_something

private

  def do_something
    # ...
  end
end

Returns:

  • (undefined)


# File 'lib/mongoid/tree.rb', line 146

Instance Method Details

#ancestor_of?(other) ⇒ Boolean

Is this document an ancestor of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is an ancestor of the other document



299
300
301
# File 'lib/mongoid/tree.rb', line 299

def ancestor_of?(other)
  other.parent_ids.include?(self.id)
end

#ancestorsMongoid::Criteria

Returns a chainable criteria for this document’s ancestors

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the documents ancestors



275
276
277
278
279
280
281
282
283
# File 'lib/mongoid/tree.rb', line 275

def ancestors
  if parent_ids.any?
    base_class.and({
      '$or' => parent_ids.map { |id| { :_id => id } }
    })
  else
    base_class.where(:_id.in => [])
  end
end

#ancestors_and_selfArray<Mongoid::Document>

Returns an array of this document’s ancestors and itself

Returns:

  • (Array<Mongoid::Document>)

    Array of the document’s ancestors and itself



289
290
291
# File 'lib/mongoid/tree.rb', line 289

def ancestors_and_self
  ancestors + [self]
end

#childrenMongoid::Criteria

Note:

Generated by Mongoid

Returns a list of the document’s children. It’s a references_many association.

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s children



# File 'lib/mongoid/tree.rb', line 194

#delete_descendantsundefined

Deletes all descendants using the database (doesn’t invoke callbacks)

Returns:

  • (undefined)


405
406
407
# File 'lib/mongoid/tree.rb', line 405

def delete_descendants
  base_class.delete_all(:conditions => { :parent_ids => self.id })
end

#depthFixnum

Returns the depth of this document (number of ancestors)

Examples:

Node.root.depth # => 0
Node.root.children.first.depth # => 1

Returns:

  • (Fixnum)

    Depth of this document



250
251
252
# File 'lib/mongoid/tree.rb', line 250

def depth
  parent_ids.count
end

#descendant_of?(other) ⇒ Boolean

Is this document a descendant of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is a descendant of the other document



325
326
327
# File 'lib/mongoid/tree.rb', line 325

def descendant_of?(other)
  self.parent_ids.include?(other.id)
end

#descendantsMongoid::Criteria

Returns a chainable criteria for this document’s descendants

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s descendants



307
308
309
# File 'lib/mongoid/tree.rb', line 307

def descendants
  base_class.where(:parent_ids => self.id)
end

#descendants_and_selfArray<Mongoid::Document>

Returns and array of this document and it’s descendants

Returns:

  • (Array<Mongoid::Document>)

    Array of the document itself and it’s descendants



315
316
317
# File 'lib/mongoid/tree.rb', line 315

def descendants_and_self
  [self] + descendants
end

#destroy_childrenundefined

Destroys all children by calling their #destroy method (does invoke callbacks)

Returns:

  • (undefined)


413
414
415
# File 'lib/mongoid/tree.rb', line 413

def destroy_children
  children.destroy_all
end

#leaf?Boolean

Is this document a leaf node (has no children)?

Returns:

  • (Boolean)

    Whether the document is a leaf node



238
239
240
# File 'lib/mongoid/tree.rb', line 238

def leaf?
  children.empty?
end

#leavesMongoid::Criteria

Returns all leaves of this document (be careful, currently involves two queries)

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s leaves



359
360
361
# File 'lib/mongoid/tree.rb', line 359

def leaves
  base_class.where(:_id.nin => base_class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
end

#move_children_to_parentundefined

Moves all children to this document’s parent

Returns:

  • (undefined)


394
395
396
397
398
399
# File 'lib/mongoid/tree.rb', line 394

def move_children_to_parent
  children.each do |c|
    c.parent = self.parent
    c.save
  end
end

#nullify_childrenundefined

Nullifies all children’s parent_id

Returns:

  • (undefined)


383
384
385
386
387
388
# File 'lib/mongoid/tree.rb', line 383

def nullify_children
  children.each do |c|
    c.parent = c.parent_id = nil
    c.save
  end
end

#parentMongoid::Document

Note:

Generated by Mongoid

Returns the document’s parent (unless it’s a root document). It’s a referenced_in association.

Returns:

  • (Mongoid::Document)

    The document’s parent document



# File 'lib/mongoid/tree.rb', line 202

#parent=(document) ⇒ Object

Note:

Generated by Mongoid

Sets this documents parent document.

Parameters:



# File 'lib/mongoid/tree.rb', line 210

#parent_idsArray<BSON::ObjectId>

Note:

Generated by Mongoid

Returns a list of the document’s parent_ids, starting with the root node.

Returns:

  • (Array<BSON::ObjectId>)

    The ids of the document’s ancestors



# File 'lib/mongoid/tree.rb', line 218

#rearrange_children!undefined

Forces rearranging of all children after next save

Returns:

  • (undefined)


367
368
369
# File 'lib/mongoid/tree.rb', line 367

def rearrange_children!
  @rearrange_children = true
end

#rearrange_children?Boolean

Will the children be rearranged after next save?

Returns:

  • (Boolean)

    Whether the children will be rearranged



375
376
377
# File 'lib/mongoid/tree.rb', line 375

def rearrange_children?
  !!@rearrange_children
end

#rootMongoid::Document

Returns this document’s root node. Returns ‘self` if the current document is a root node

Examples:

node = Node.find(...)
node.root

Returns:

  • (Mongoid::Document)

    The documents root node



263
264
265
266
267
268
269
# File 'lib/mongoid/tree.rb', line 263

def root
  if parent_ids.present?
    base_class.find(parent_ids.first)
  else
    self.root? ? self : self.parent.root
  end
end

#root?Boolean

Is this document a root node (has no parent)?

Returns:

  • (Boolean)

    Whether the document is a root node



230
231
232
# File 'lib/mongoid/tree.rb', line 230

def root?
  parent_id.nil?
end

#sibling_of?(other) ⇒ Boolean

Is this document a sibling of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is a sibling of the other document



351
352
353
# File 'lib/mongoid/tree.rb', line 351

def sibling_of?(other)
  self.parent_id == other.parent_id
end

#siblingsMongoid::Criteria

Returns this document’s siblings

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s siblings



333
334
335
# File 'lib/mongoid/tree.rb', line 333

def siblings
  siblings_and_self.excludes(:id => self.id)
end

#siblings_and_selfMongoid::Criteria

Returns this document’s siblings and itself

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s siblings and itself



341
342
343
# File 'lib/mongoid/tree.rb', line 341

def siblings_and_self
  base_class.where(:parent_id => self.parent_id)
end