• Stars
    star
    100
  • Rank 340,703 (Top 7 %)
  • Language
    JavaScript
  • License
    Other
  • Created almost 12 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Educational repository demonstrating approaches for storing tree structures with NoSQL database MongoDB

Storing Tree like Structures With MongoDB

Educational repository demonstrating approaches for storing tree structures with NoSQL database MongoDB

Background

In a real life almost any project deals with the tree structures. Different kinds of taxonomies, site structures etc require modelling of hierarhy relations. In this article I will illustrate using five typical approaches plus one combination of operating with hierarchy data on example of the MongoDB database. Those approaches are:

  • Model Tree Structures with Child References
  • Model Tree Structures with Parent References
  • Model Tree Structures with an Array of Ancestors
  • Model Tree Structures with Materialized Paths
  • Model Tree Structures with Nested Sets

Note: article is inspired by another article 'Model Tree Structures in MongoDB' by MongoDB, but does not copy it, but provides additional examples on typical operations with tree management. Please refer for 10gen article to get more solid understanding of the approach.

As a demo dataset I use some fake eshop goods taxonomy.

Tree

Challenges to address

In a typical site scenario, we should be able

  • Operate with tree (insert new node under specific parent, update/remove existing node, move node across the tree)
  • Get path to node (for example, in order to be build the breadcrumb section)
  • Get all node descendants (in order to be able, for example, to select goods from more general category, like 'Cell Phones and Accessories' which should include goods from all subcategories.

On each of the examples below we:

  • Add new node called 'LG' under electronics
  • Move 'LG' node under Cell_Phones_And_Smartphones node
  • Remove 'LG' node from the tree
  • Get child nodes of Electronics node
  • Get path to 'Nokia' node
  • Get all descendants of the 'Cell_Phones_and_Accessories' node

Please refer to image above for visual representation.

Tree structure with parent reference

This is most commonly used approach. For each node we store (ID, ParentReference, Order).

Operating with tree

Pretty simple, but changing the position of the node withing siblings will require additional calculations. You might want to set high numbers like item position * 10^6 for order in order to be able to set new node order as trunc (lower sibling order - higher sibling order)/2 - this will give you enough operations, until you will need to traverse whole the tree and set the order defaults to big numbers again.

Adding new node

var existingelemscount = db.categoriesPCO.find({parent:'Electronics'}).count();
var neworder = (existingelemscount+1)*10;
db.categoriesPCO.insert({_id:'LG', parent:'Electronics', someadditionalattr:'test', order:neworder})
//{ "_id" : "LG", "parent" : "Electronics", "someadditionalattr" : "test", "order" : 40 }

Updating/moving the node

existingelemscount = db.categoriesPCO.find({parent:'Cell_Phones_and_Smartphones'}).count();
neworder = (existingelemscount+1)*10;
db.categoriesPCO.update({_id:'LG'},{$set:{parent:'Cell_Phones_and_Smartphones', order:neworder}});
//{ "_id" : "LG", "order" : 60, "parent" : "Cell_Phones_and_Smartphones", "someadditionalattr" : "test" }

Node removal

db.categoriesPCO.remove({_id:'LG'});

Getting node children, ordered

db.categoriesPCO.find({$query:{parent:'Electronics'}, $orderby:{order:1}})
//{ "_id" : "Cameras_and_Photography", "parent" : "Electronics", "order" : 10 }
//{ "_id" : "Shop_Top_Products", "parent" : "Electronics", "order" : 20 }
//{ "_id" : "Cell_Phones_and_Accessories", "parent" : "Electronics", "order" : 30 }

Getting all node descendants

Unfortunately, also involves recursive operation

var descendants=[]
var stack=[];
var item = db.categoriesPCO.findOne({_id:"Cell_Phones_and_Accessories"});
stack.push(item);
while (stack.length>0){
    var currentnode = stack.pop();
    var children = db.categoriesPCO.find({parent:currentnode._id});
    while(true === children.hasNext()) {
        var child = children.next();
        descendants.push(child._id);
        stack.push(child);
    }
}


descendants.join(",")
//Cell_Phones_and_Smartphones,Headsets,Batteries,Cables_And_Adapters,Nokia,Samsung,Apple,HTC,Vyacheslav

Getting path to node

Unfortunately involves recursive operations

var path=[]
var item = db.categoriesPCO.findOne({_id:"Nokia"})
while (item.parent !== null) {
    item=db.categoriesPCO.findOne({_id:item.parent});
    path.push(item._id);
}

path.reverse().join(' / ');
//Electronics / Cell_Phones_and_Accessories / Cell_Phones_and_Smartphones

Indexes

Recommended index is on fields parent and order

db.categoriesPCO.ensureIndex( { parent: 1, order:1 } )

Tree structure with childs reference

For each node we store (ID, ChildReferences).

Please note, that in this case we do not need order field, because Childs collection already provides this information. Most of languages respect the array order. If this is not in case for your language, you might consider additional coding to preserve order, however this will make things more complicated.

Adding new node

db.categoriesCRO.insert({_id:'LG', childs:[]});
db.categoriesCRO.update({_id:'Electronics'},{  $addToSet:{childs:'LG'}});
//{ "_id" : "Electronics", "childs" : [ 	"Cameras_and_Photography", 	"Shop_Top_Products", 	"Cell_Phones_and_Accessories", 	"LG" ] }

Updating/moving the node

rearranging order under the same parent

db.categoriesCRO.update({_id:'Electronics'},{$set:{"childs.1":'LG',"childs.3":'Shop_Top_Products'}});
//{ "_id" : "Electronics", "childs" : [ 	"Cameras_and_Photography", 	"LG", 	"Cell_Phones_and_Accessories", 	"Shop_Top_Products" ] }

moving the node

db.categoriesCRO.update({_id:'Cell_Phones_and_Smartphones'},{  $addToSet:{childs:'LG'}});
db.categoriesCRO.update({_id:'Electronics'},{$pull:{childs:'LG'}});
//{ "_id" : "Cell_Phones_and_Smartphones", "childs" : [ "Nokia", "Samsung", "Apple", "HTC", "Vyacheslav", "LG" ] }

Node removal

db.categoriesCRO.update({_id:'Cell_Phones_and_Smartphones'},{$pull:{childs:'LG'}})
db.categoriesCRO.remove({_id:'LG'});

Getting node children, ordered

Note requires additional client side sorting by parent array sequence

var parent = db.categoriesCRO.findOne({_id:'Electronics'})
db.categoriesCRO.find({_id:{$in:parent.childs}})

Result set:

{ "_id" : "Cameras_and_Photography", "childs" : [ 	"Digital_Cameras", 	"Camcorders", 	"Lenses_and_Filters", 	"Tripods_and_supports", 	"Lighting_and_studio" ] }
{ "_id" : "Cell_Phones_and_Accessories", "childs" : [ 	"Cell_Phones_and_Smartphones", 	"Headsets", 	"Batteries", 	"Cables_And_Adapters" ] }
{ "_id" : "Shop_Top_Products", "childs" : [ "IPad", "IPhone", "IPod", "Blackberry" ] }

//parent:
{
	"_id" : "Electronics",
	"childs" : [
		"Cameras_and_Photography",
		"Cell_Phones_and_Accessories",
		"Shop_Top_Products"
	]
}

As you see, we have ordered array childs, which can be used to sort the result set on a client

Getting all node descendants

var descendants=[]
var stack=[];
var item = db.categoriesCRO.findOne({_id:"Cell_Phones_and_Accessories"});
stack.push(item);
while (stack.length>0){
    var currentnode = stack.pop();
    var children = db.categoriesCRO.find({_id:{$in:currentnode.childs}});

    while(true === children.hasNext()) {
        var child = children.next();
        descendants.push(child._id);
        if(child.childs.length>0){
          stack.push(child);
        }
    }
}

//Batteries,Cables_And_Adapters,Cell_Phones_and_Smartphones,Headsets,Apple,HTC,Nokia,Samsung
descendants.join(",")

Getting path to node

var path=[]
var item = db.categoriesCRO.findOne({_id:"Nokia"})
while ((item=db.categoriesCRO.findOne({childs:item._id}))) {
    path.push(item._id);
}

path.reverse().join(' / ');
//Electronics / Cell_Phones_and_Accessories / Cell_Phones_and_Smartphones

Indexes

Recommended index is putting index on childs:

db.categoriesCRO.ensureIndex( { childs: 1 } )

Tree structure Model an Array of Ancestors

For each node we store (ID, ParentReference, AncestorReferences)

Adding new node

var ancestorpath = db.categoriesAAO.findOne({_id:'Electronics'}).ancestors;
ancestorpath.push('Electronics')
db.categoriesAAO.insert({_id:'LG', parent:'Electronics',ancestors:ancestorpath});
//{ "_id" : "LG", "parent" : "Electronics", "ancestors" : [ "Electronics" ] }

Updating/moving the node

moving the node

ancestorpath = db.categoriesAAO.findOne({_id:'Cell_Phones_and_Smartphones'}).ancestors;
ancestorpath.push('Cell_Phones_and_Smartphones')
db.categoriesAAO.update({_id:'LG'},{$set:{parent:'Cell_Phones_and_Smartphones', ancestors:ancestorpath}});
//{ "_id" : "LG", "ancestors" : [ 	"Electronics", 	"Cell_Phones_and_Accessories", 	"Cell_Phones_and_Smartphones" ], "parent" : "Cell_Phones_and_Smartphones" }

Node removal

db.categoriesAAO.remove({_id:'LG'});

Getting node children, unordered

Note unless you introduce the order field, it is impossible to get ordered list of node children. You should consider another approach if you need order.

db.categoriesAAO.find({$query:{parent:'Electronics'}})

Getting all node descendants

there are two options to get all node descendants. One is classic through recursion:

var ancestors = db.categoriesAAO.find({ancestors:"Cell_Phones_and_Accessories"},{_id:1});
while(true === ancestors.hasNext()) {
       var elem = ancestors.next();
       descendants.push(elem._id);
   }
descendants.join(",")
//Cell_Phones_and_Smartphones,Headsets,Batteries,Cables_And_Adapters,Nokia,Samsung,Apple,HTC,Vyacheslav

second is using aggregation framework introduced in MongoDB 2.2:

var aggrancestors = db.categoriesAAO.aggregate([
    {$match:{ancestors:"Cell_Phones_and_Accessories"}},
    {$project:{_id:1}},
    {$group:{_id:{},ancestors:{$addToSet:"$_id"}}}
])

descendants = aggrancestors.result[0].ancestors
descendants.join(",")
//Vyacheslav,HTC,Samsung,Cables_And_Adapters,Batteries,Headsets,Apple,Nokia,Cell_Phones_and_Smartphones

Tree structure using Materialized Path

For each node we store (ID, PathToNode)

Adding new node

var ancestorpath = db.categoriesMP.findOne({_id:'Electronics'}).path;
ancestorpath += 'Electronics,'
db.categoriesMP.insert({_id:'LG', path:ancestorpath});
//{ "_id" : "LG", "path" : "Electronics," }

Updating/moving the node

moving the node

ancestorpath = db.categoriesMP.findOne({_id:'Cell_Phones_and_Smartphones'}).path;
ancestorpath +='Cell_Phones_and_Smartphones,'
db.categoriesMP.update({_id:'LG'},{$set:{path:ancestorpath}});
//{ "_id" : "LG", "path" : "Electronics,Cell_Phones_and_Accessories,Cell_Phones_and_Smartphones," }

Node removal

db.categoriesMP.remove({_id:'LG'});

Getting node children, unordered

Note unless you introduce the order field, it is impossible to get ordered list of node children. You should consider another approach if you need order.

db.categoriesMP.find({$query:{path:'Electronics,'}})
//{ "_id" : "Cameras_and_Photography", "path" : "Electronics," }
//{ "_id" : "Shop_Top_Products", "path" : "Electronics," }
//{ "_id" : "Cell_Phones_and_Accessories", "path" : "Electronics," }

Getting all node descendants

Single select, regexp starts with ^ which allows using the index for matching

var descendants=[]
var item = db.categoriesMP.findOne({_id:"Cell_Phones_and_Accessories"});
var criteria = '^'+item.path+item._id+',';
var children = db.categoriesMP.find({path: { $regex: criteria, $options: 'i' }});
while(true === children.hasNext()) {
  var child = children.next();
  descendants.push(child._id);
}


descendants.join(",")
//Cell_Phones_and_Smartphones,Headsets,Batteries,Cables_And_Adapters,Nokia,Samsung,Apple,HTC,Vyacheslav

Getting path to node

We can obtain path directly from node without issuing additional selects.

var path=[]
var item = db.categoriesMP.findOne({_id:"Nokia"})
print (item.path)
//Electronics,Cell_Phones_and_Accessories,Cell_Phones_and_Smartphones,

Indexes

Recommended index is putting index on path

  db.categoriesAAO.ensureIndex( { path: 1 } )

Tree structure using Nested Sets

For each node we store (ID, left, right).

Left field also can be treated as an order field

Adding new node

Please refer to image above. Assume, we want to insert LG node after shop_top_products(14,23). New node would have left value of 24, affecting all remaining left values according to traversal rules, and will have right value of 25, affecting all remaining right values including root one.

Steps:

  • take next node in traversal tree
  • new node will have left value of the following sibling and right value - incremented by two following sibling's left one
  • now we have to create the place for the new node. Update affects right values of all ancestor nodes and also affects all nodes that remain for traversal
  • Only after creating place new node can be inserted
var followingsibling = db.categoriesNSO.findOne({_id:"Cell_Phones_and_Accessories"});

var newnode = {_id:'LG', left:followingsibling.left,right:followingsibling.left+1}

db.categoriesNSO.update({right:{$gt:followingsibling.right}},{$inc:{right:2}}, false, true)

db.categoriesNSO.update({left:{$gte:followingsibling.left}, right:{$lte:followingsibling.right}},{$inc:{left:2, right:2}}, false, true)

db.categoriesNSO.insert(newnode)

Let's check the result:

 +-Electronics (1,46)
     +---Cameras_and_Photography (2,13)
           +------Digital_Cameras (3,4)
           +------Camcorders (5,6)
           +------Lenses_and_Filters (7,8)
           +------Tripods_and_supports (9,10)
           +------Lighting_and_studio (11,12)
       +----Shop_Top_Products (14,23)
           +------IPad (15,16)
           +------IPhone (17,18)
           +------IPod (19,20)
           +------Blackberry (21,22)
       +----LG (24,25)
       +----Cell_Phones_and_Accessories (26,45)
           +------Cell_Phones_and_Smartphones (27,38)
                 +---------Nokia (28,29)
                 +---------Samsung (30,31)
                 +---------Apple (32,33)
                 +---------HTC (34,35)
                 +---------Vyacheslav (36,37)
             +-------Headsets (39,40)
             +-------Batteries (41,42)
             +-------Cables_And_Adapters (43,44)

Node removal

While potentially rearranging node order within same parent is identical to exchanging node's left and right values, the formal way of moving the node is first removing node from the tree and later inserting it to new location. Node: node removal without removing it's childs is out of scope for this article. For now, we assume, that node to remove has no children, i.e. right-left=1

Steps are identical to adding the node - i.e. we adjusting the space by decreasing affected left/right values, and removing original node.

var nodetoremove = db.categoriesNSO.findOne({_id:"LG"});

if((nodetoremove.right-nodetoremove.left-1)>0.001) {
    print("Only node without childs can be removed")
    exit
}

var followingsibling = db.categoriesNSO.findOne({_id:"Cell_Phones_and_Accessories"});

//update all remaining nodes
db.categoriesNSO.update({right:{$gt:nodetoremove.right}},{$inc:{right:-2}}, false, true)
db.categoriesNSO.update({left:{$gt:nodetoremove.right}},{$inc:{left:-2}}, false, true)
db.categoriesNSO.remove({_id:"LG"});

Let's check result:

 +-Electronics (1,44)
   +--Cameras_and_Photography (2,13)
         +-----Digital_Cameras (3,4)
         +-----Camcorders (5,6)
         +-----Lenses_and_Filters (7,8)
         +-----Tripods_and_supports (9,10)
         +-----Lighting_and_studio (11,12)
     +---Shop_Top_Products (14,23)
         +-----IPad (15,16)
         +-----IPhone (17,18)
         +-----IPod (19,20)
         +-----Blackberry (21,22)
     +---Cell_Phones_and_Accessories (24,43)
         +-----Cell_Phones_and_Smartphones (25,36)
               +--------Nokia (26,27)
               +--------Samsung (28,29)
               +--------Apple (30,31)
               +--------HTC (32,33)
               +--------Vyacheslav (34,35)
           +------Headsets (37,38)
           +------Batteries (39,40)
           +------Cables_And_Adapters (41,42)

Updating/moving the single node

moving the node can be within same parent, or to another parent. If the same parent, and nodes are without childs, than you need just to exchange nodes (left,right) pairs.

Formal way is to remove node and insert to new destination, thus the same restriction apply - only node without children can be moved. If you need to move subtree, consider creating mirror of the existing parent under new location, and move nodes under the new parent one by one. Once all nodes moved, remove obsolete old parent.

As an example, lets move LG node from the insertion example under the Cell_Phones_and_Smartphones node, as a last sibling (i.e. you do not have following sibling node as in the insertion example)

Step 1 would be to remove LG node from tree using node removal procedure described above Step2 is to take right value of the new parent. New node will have left value of the parent's right value and right value - incremented by one parent's right one Now we have to create the place for the new node: update affects right values of all nodes on a further traversal path

var newparent = db.categoriesNSO.findOne({_id:"Cell_Phones_and_Smartphones"});
var nodetomove = {_id:'LG', left:newparent.right,right:newparent.right+1}


//3th and 4th parameters: false stands for upsert=false and true stands for multi=true
db.categoriesNSO.update({right:{$gte:newparent.right}},{$inc:{right:2}}, false, true)
db.categoriesNSO.update({left:{$gte:newparent.right}},{$inc:{left:2}}, false, true)

db.categoriesNSO.insert(nodetomove)

Let's check result:

 +-Electronics (1,46)
   +--Cameras_and_Photography (2,13)
         +-----Digital_Cameras (3,4)
         +-----Camcorders (5,6)
         +-----Lenses_and_Filters (7,8)
         +-----Tripods_and_supports (9,10)
         +-----Lighting_and_studio (11,12)
     +---Shop_Top_Products (14,23)
         +-----IPad (15,16)
         +-----IPhone (17,18)
         +-----IPod (19,20)
         +-----Blackberry (21,22)
     +---Cell_Phones_and_Accessories (24,45)
         +-----Cell_Phones_and_Smartphones (25,38)
                 +---------Nokia (26,27)
                 +---------Samsung (28,29)
                 +---------Apple (30,31)
                 +---------HTC (32,33)
                 +---------Vyacheslav (34,35)
                 +---------LG (36,37)
             +-------Headsets (39,40)
             +-------Batteries (41,42)
             +-------Cables_And_Adapters (43,44)

Getting node children, unordered

Note, unless all node childs have no childrens theirselfs it is impossible to get node direct childs. Consider using modified approach of combining NestedSets with parent field.

Getting all node descendants

This is core stength of this approach - all descendants retrieved using one select to DB. Moreover, by sorting by node left - the dataset is ready for traversal in a correct order

var descendants=[]
var item = db.categoriesNSO.findOne({_id:"Cell_Phones_and_Accessories"});
print ('('+item.left+','+item.right+')')
var children = db.categoriesNSO.find({left:{$gt:item.left}, right:{$lt:item.right}}).sort(left:1);
while(true === children.hasNext()) {
  var child = children.next();
  descendants.push(child._id);
}


descendants.join(",")
//Cell_Phones_and_Smartphones,Headsets,Batteries,Cables_And_Adapters,Nokia,Samsung,Apple,HTC,Vyacheslav

Getting path to node

Retrieving path to node is also elegant and can be done using single query to database

var path=[]
var item = db.categoriesNSO.findOne({_id:"Nokia"})

var ancestors = db.categoriesNSO.find({left:{$lt:item.left}, right:{$gt:item.right}}).sort({left:1})
while(true === ancestors.hasNext()) {
  var child = ancestors.next();
  path.push(child._id);
}

path.join('/')
// Electronics/Cell_Phones_and_Accessories/Cell_Phones_and_Smartphones

Indexes

Recommended index is putting index on left and right values:

  db.categoriesAAO.ensureIndex( { left: 1, right:1 } )

Tree structure using combination of Nested Sets and classic Parent reference with order approach

For each node we store (ID, Parent, Order,left, right).

Left field also is treated as an order field, so we could omit order field. But from other hand we can leave it, so we can use Parent Reference with order data to reconstruct left/right values in case of accidental corruption, or, for example during initial import.

Adding new node

Adding new node can be adopted from Nested Sets in this manner:

var followingsibling = db.categoriesNSO.findOne({_id:"Cell_Phones_and_Accessories"});
var previoussignling = db.categoriesNSO.findOne({_id:"Shop_Top_Products"});
var neworder = parseInt((followingsibling.order + previoussignling.order)/2);
var newnode = {_id:'LG', left:followingsibling.left,right:followingsibling.left+1, parent:followingsibling.parent, order:neworder};
db.categoriesNSO.update({right:{$gt:followingsibling.right}},{$inc:{right:2}}, false, true)
db.categoriesNSO.update({left:{$gte:followingsibling.left}, right:{$lte:followingsibling.right}},{$inc:{left:2, right:2}}, false, true)

db.categoriesNSO.insert(newnode)

Before insertion

          +----Cameras_and_Photography (2,13)  ord.[10]
          +-----Shop_Top_Products (14,23)  ord.[20]
          +-----Cell_Phones_and_Accessories (26,45)  ord.[30]

After insertion:

   +--Electronics (1,46) 
           +----Cameras_and_Photography (2,13)  ord.[10]
                       +-------Digital_Cameras (3,4)  ord.[10]
                       +-------Camcorders (5,6)  ord.[20]
                       +-------Lenses_and_Filters (7,8)  ord.[30]
                       +-------Tripods_and_supports (9,10)  ord.[40]
                       +-------Lighting_and_studio (11,12)  ord.[50]
           +-----Shop_Top_Products (14,23)  ord.[20]
                       +-------IPad (15,16)  ord.[10]
                       +-------IPhone (17,18)  ord.[20]
                       +-------IPod (19,20)  ord.[30]
                       +-------Blackberry (21,22)  ord.[40]
           +-----LG (24,25)  ord.[25]
           +-----Cell_Phones_and_Accessories (26,45)  ord.[30]
                       +-------Cell_Phones_and_Smartphones (27,38)  ord.[10]
                                   +----------Nokia (28,29)  ord.[10]
                                   +----------Samsung (30,31)  ord.[20]
                                   +----------Apple (32,33)  ord.[30]
                                   +----------HTC (34,35)  ord.[40]
                                   +----------Vyacheslav (36,37)  ord.[50]
                       +--------Headsets (39,40)  ord.[20]
                       +--------Batteries (41,42)  ord.[30]
                       +--------Cables_And_Adapters (43,44)  ord.[40]

Updating/moving the single node

Identical to insertion approach

Node removal

Approach from Nested Sets is used.

Getting node children, ordered

Now is possible by using (Parent,Order) pair

db.categoriesNSO.find({parent:"Electronics"}).sort({order:1});
/*

{ "_id" : "Cameras_and_Photography", "parent" : "Electronics", "order" : 10, "left" : 2, "right" : 13 }
{ "_id" : "Shop_Top_Products", "parent" : "Electronics", "order" : 20, "left" : 14, "right" : 23 }
{ "_id" : "LG", "left" : 24, "right" : 25, "parent" : "Electronics", "order" : 25 }
{ "_id" : "Cell_Phones_and_Accessories", "parent" : "Electronics", "order" : 30, "left" : 26, "right" : 45 }

*/

Getting all node descendants

Approach from Nested Sets is used.

Getting path to node

Approach from nested sets is used

Code in action

Code can be downloaded from repository https://github.com/Voronenko/Storing_TreeView_Structures_WithMongoDB

All files are packaged according to the following naming convention:

  • MODELReference.js - initialization file with tree data for MODEL approach
  • MODELReference_operating.js - add/update/move/remove/get children examples
  • MODELReference_pathtonode.js - code illustrating how to obtain path to node
  • MODELReference_nodedescendants.js - code illustrating how to retrieve all the descendands of the node

Points of interest

Please note, that MongoDB does not provide ACID transactions. This means, that for update operations splitted into separate update commands, your application should implement additional code to support your code specific transactions.

Formal advise from 10gen is following:

  • The Parent Reference pattern provides a simple solution to tree storage, but requires multiple queries to retrieve subtrees
  • The Child References pattern provides a suitable solution to tree storage as long as no operations on subtrees are necessary. This pattern may also provide a suitable solution for storing graphs where a node may have multiple parents.
  • The Array of Ancestors pattern - no specific advantages unless you constantly need to get path to the node

You are free to mix patterns (by introducing order field, etc) to match the data operations required to your application.

More Repositories

1

PHPOTP

Php Implementation of the OTP algorythm
PHP
132
star
2

hashi_vault_utils

handy batches to execute common tasks with vault
Shell
81
star
3

gitflow-release

Approach for implementing git-flow releasing model
Shell
52
star
4

ansible-developer_recipes

Helper ansible repository for my devbox box configuration. Suitable for: LAMP, MEAN stack, Java stack [DevOps, Ansible]
Python
34
star
5

traefik2-compose-template

Check out fiks.im - unobtrusive local development with traefik2, docker and green sealed wildcard certs with letsencrypt. Introducing ultimate local development environment for docker projects with traefik2 and letsencrypt
Shell
24
star
6

devops-jenkins-box-template

Bootstrap template to provision your agency own Jenkins server
Shell
22
star
7

awesome-plantuml

17
star
8

dotfiles

portable configuration files for unix environment
Shell
15
star
9

devops-tf-eks

terraform baked AWS kubernetes cluster (EKS) - 1.18 compatible
HCL
15
star
10

JSOTP

Compact One Time Password Generator (RFC6238)
JavaScript
13
star
11

fightcodegame

Fun with http://fightcodegame.com/ - possibility to concentrate on strategies, and have more component code.
JavaScript
11
star
12

jumpbox

Creates secured box for accessing internal networks
Shell
10
star
13

chromecastdemo

Quick demo on integrating chromecast into website [javascript, google chromecast]
JavaScript
10
star
14

k3s-mini

Running local kubernetes cluster with k3s, traefik2 and letsencrypt
HCL
9
star
15

winfiles

portable configuration files for windows environment
PowerShell
9
star
16

toggl_invoice

Helper script to generate invoice extract from toggl into Google Sheet
JavaScript
7
star
17

alexa-echodot-shell

JavaScript
6
star
18

devops-gitlab-runner-compose

Docker-compose for dockerized gitlab runner
Shell
6
star
19

goip_exporter

Simple exporter for GOIP gsm device
Go
5
star
20

ansible_vpc_ppsubnet_wnat

Automating http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html creation on aws
Python
5
star
21

devops-ruby-app-demo

Demo repository illustrating approaches for automated ruby application deployment
Shell
4
star
22

runbooks-mkdocs

Template repository aiming creation of the runbooks combined with basic lightweight documentation portal based on mkdocs, plantuml diagrams, and set of selected plugins
Shell
4
star
23

devops-ansible-container-demo

Can we use ansible-container as a tool to build Docker images and orchestrate containers using only Ansible playbooks?
Makefile
4
star
24

ProjectDocs

This is boilerplate for project documentation portal. Example can be seen here
JavaScript
4
star
25

devops-traefik-1-deploy-template

Education repository: using ansible to deploy dockerized applications to VPS with traefik.io
Shell
3
star
26

grafana_kapitan

Grafana dashboards generator with grafana and kapitan
Makefile
3
star
27

kong-compose-template

Lua
3
star
28

win-k8s-croco

Fun POC on using kubernetes built-in into docker for windows
Makefile
3
star
29

devops-terraform-esxi-boilerplate

POC for managing free esxi instance with opensource terraform provider via ssh workaround
HCL
3
star
30

errbot-grafana

Opinionated errbot plugin for grafana. Suitable for use with https://github.com/softasap/sa-grafana, https://github.com/softasap/sa-chatops-errbot as well as with any custom installation.
Python
3
star
31

GO-IOS-DELPHI

Proof of concept: simplified 'GO' IOS game on 3x3 field written in Delphi
Component Pascal
2
star
32

chef-developer_bootstrap

Helper for unattended installing of development environments (LAMP, Mean, Java) [DevOps, Chef, Vagrant]
Shell
2
star
33

wordpress-classic-app-demo

Approach for combining terraform and ansible to deploy lamp server with wordpress application
PHP
2
star
34

devops-terraform-ansible-boilerplate

Boilerplate for deployment projects involving terraform and ansible
HCL
2
star
35

vscode-plantuml-stdlib-snippets

PlantUML stdlib snippets aiming quicker creation of the nice visual diagrams
2
star
36

kong-plugin-sa-jwt-claims-validate

Kong2 compatible plugin for validation of the custom JWT token claims
Lua
2
star
37

self-hosted-prerender

Dockerfile
2
star
38

sa_grafonnet_lib

"Sidecar" to grafonnet-lib for AWS/ECS visualization - set of panels, metrics, templates to visualize state of your ECS clusters
2
star
39

ps_oneliners

POC on creating one liner bootstrap powershell scripts with parameters
PowerShell
2
star
40

errbot-prometheus-alertmanager

Opinionated errbot plugin for Prometheus Alert Manager. Suitable for use with https://github.com/softasap/sa-prometheus-alertmanager, https://github.com/softasap/sa-chatops-errbot as well as with any custom installation.
Python
2
star
41

aws-key-importer

Mini utility to push pub key to selected aws region
Go
1
star
42

yiinano

Minimalist yii installation with Rich Exception View support. Allows to implement yii solution that uses minimal amount of files to be uploaded. (For specific linux based devices, or low space PC sticks)
PHP
1
star
43

esxi-windows-gitlab-runner

Self-hosted windows runner based on esxi backed instance
HCL
1
star
44

docker-s6-nginx-php-fpm

Base example covering mocking nginx/php-fpm environment with activated xdebug support
Dockerfile
1
star
45

docker-croco-hunter-image

Docker croco-hunter image defaulting to 7777
Go
1
star
46

yii-config

Helper extension with aim to speedup config changes required by modules
PHP
1
star
47

instancegarden

Set of starters to test stuff in vagrant or ESXi
HCL
1
star
48

route53-letsencrypt-policy

Approach to introduce letsencrypt wildcard certificates on aws with a bit limited credentials set.
HCL
1
star
49

yii-stub

Composer based application template for yii with extensible options
PHP
1
star
50

cdci-tf-ansible

cdci image with ansible and terraform
Shell
1
star
51

cdci-helm-kubectl

Basic cdci deployment container with kubectl and helm
Shell
1
star
52

voronenko

CV repo based info site with mkdocs +
HTML
1
star
53

pre-commit-cdci

CircleCI/GitlabCI config validation
Shell
1
star
54

okd

Spins up 3.11 okd cluster on vagrant (master and 2 compute nodes)
Shell
1
star
55

poc-terraform-ansible-bridge

Proof of concept demostration of sharing ansible variables file with terraform provisioner
Shell
1
star
56

armfiles

Arm optimized dotfiles, less heavy than usual dotfiles
Shell
1
star
57

devops-bootstrap-box-template

Basic repository for setting up secured remove ubuntu 14.04 LTS box
Shell
1
star
58

lamp-box

"Umbrella repository" approach, that allows wrapping potentially any project into vagrant environment
Shell
1
star
59

debug-pod

Dockerfile
1
star
60

MapReduce-assigments

Self studying on Map-Reduce course http://lintool.github.com/MapReduce-course-2013s/assignments.html
JavaScript
1
star
61

fiks.im

fiks.im - neutral domain for local debugging
Makefile
1
star
62

awx-docker-compose

Docker compose based instance of the ansible awx
Python
1
star