Skip to content
Steven edited this page Feb 24, 2017 · 21 revisions

This article will go over how it is easy to create interconnected data with GUN's graph features, combining key/value, relational, and document based data together. It will also be a great introductory guide on how to use pretty much every one of GUN's API methods.

Note: This article requires gun v0.5.x or above.

First let's instantiate the database.

var gun = Gun();

Then we'll add some people to our database using a simple key/value approach.

var alice = gun.get('person/alice').put({name: 'alice', age: 22});
var bob = gun.get('person/bob').put({name: 'bob', age: 24});
var carl = gun.get('person/carl').put({name: 'carl', age: 16});
var dave = gun.get('person/dave').put({name: 'dave', age: 42});

Note: If no data is found on the key ('person/alice', etc.) when we .get it, gun will implicitly create and update it upon a .put. This is useful and convenient, but can be problematic for some types of apps. If you want to check if the data does not exist, use .not first.

What if we want to get their data? We can either chain off of the reference directly or get it again:

alice.on(function(node){
  console.log('Subscribed to Alice!', node);
});

gun.get('person/bob').val(function(node){
  console.log('Bob!', node);
});

Note: GUN is a functional reactive database for streaming event driven data, gotta hate buzzwords - right? This means that .on subscribes to realtime updates, and may get called many times. Meanwhile .val grabs the data once, which is useful for procedural operations.

Now lets add all the people into a set, you can think of this as a table in relational databases or a collection in NoSQL databases.

var people = gun.get('people');
people.set(alice);
people.set(bob);
people.set(carl);
people.set(dave);

Note: .get and .put are the core API of gun, everything else is just a convenient utility that wraps around them for specific uses - like .set for inserting records.

It is now easy to iterate through our list of people.

people.map().val(function(person){
  console.log("The person is", person);
});

Note: If .map is given no callback, it simply iterates over each item in the list "as is" - thus acting like a for each loop in javascript. Also, everything is continuously evaluating in GUN, including .map, so it will get called when new items are added as well as when an item is updated. It does not iterate through the whole list again every time, just the changes. This is great for realtime applications.

Next we want to add a startup that some of these people work at. Document oriented data does a perfect job at capturing the hierarchy of a company. Let's do that with the following:

var company = gun.get('startup/hype').put({
  name: "hype",
  profitable: false,
  address: {
    street: "123 Hipster Lane",
    city: "San Francisco",
    state: "CA",
    country: "USA"
  }
});

Now let's read it out!

company.val(function(startup){
  console.log("The startup:", startup);
});

Note: The data given in the callback is only 1 layer deep to keep things fast. What you'll see logged out on startup.address is not the address itself, but a pointer to the address. Because documents can be of any depth, GUN only streams out what you need by default, thus optimizing bandwidth.

So what if you want to actually access the city property on the company's address then? .path lets you traverse into your document using the standard dot notation syntax popular in javascript and document databases.

company.path('address.city').val(function(value, key){
  console.log("What is the city?", value);
});

Note: Sometimes a property name might have a '.' in it itself, like if a decimal 0.33 is used as the field. This is okay, because .path just wraps around .get. So you can escape the decimal by doing company.get('address').get('city') instead. Also, the key in the callback is always the last property name in the field path.

Good news! We just found out the company got funding and moved to a new office! Let's go ahead and update it.

gun.get('startup/hype').put({ // or you could do `company.put({` instead.
  funded: true,
  address: {
    street: "999 Expensive Boulevard"
  }
});

Note: GUN saves everything as a partial update, so you do not have to re-save the entire object every time (in fact, this should be avoided)! It automatically merges the updates for you by doing conflict resolution on the data. This lets us update only the pieces we want without worrying about overwriting the whole document.

However documents in isolation are not very useful. Let's connect things and turn everything into a graph!

var employees = company.path('employees');
employees.set(dave);
employees.set(alice);
employees.set(bob);

alice.path('spouse').put(bob);
bob.path('spouse').put(alice);

alice.path('spouse').path('employer').put(company);
alice.path('employer').put(company);

dave.path('kids').set(carl);
carl.path('dad').put(dave);

carl.path('friends').set(alice);
carl.path('friends').set(bob);

Note: We can have 1-1, 1-N, N-N relationships. By default every relationship is a "directed" graph (it only goes in one direction), so if you want bi-directional relationships you must explicitly save the data as being so (like with Dave and his kid, Carl). If you want to have meta information about the relationship, simply create an "edge" node that both properties point to instead. Many graph databases do this by default, but because not all data structures require it, gun leaves it to you to specify.

Finally, let's read some data out. Starting with getting a key/value, then navigating into a document, then mapping over a table, then traversing into one of the columns and printing out all the values!

gun.get('person/alice').path('spouse.employer.employees').map().path('name').val(function(data, key){
  console.log("The employee's", key, data);
});

Awesome, now run it all together: http://jsbin.com/mivaciwupa/edit?js,console (Hit "Run", all logs except for the last one have been commented out).

GUN is that easy! And it all syncs in realtime across devices! Imagine what you can build?

Whatever it is (except for banking), we hope you are excited and tackle it with gun! Make sure you join the chat room (everybody is nice and helpful there) and ask questions or complain about bugs/problems. Or if you think your company might be interested in using gun, we have some great partnership plans (as well as some donation options, if you want to personally contribute some yummy meals to our tummy)!

This wiki is where all the GUN website documentation comes from.

You can read it here or on the website, but the website has some special features like rendering some markdown extensions to create interactive coding tutorials.

Please feel free to improve the docs itself, we need contributions!

Clone this wiki locally