Skip to content
START FOR FREE
START FOR FREE
  • SUPPORT
  • COMMUNITY
Menu
  • SUPPORT
  • COMMUNITY
MENUMENU
  • Products
    • The World’s Fastest and Most Scalable Graph Platform

      LEARN MORE

      Watch a TigerGraph Demo

      TIGERGRAPH CLOUD

      • Overview
      • TigerGraph Cloud Suite
      • FAQ
      • Pricing

      USER TOOLS

      • GraphStudio
      • Insights
      • Application Workbenches
      • Connectors and Drivers
      • Starter Kits
      • openCypher Support

      TIGERGRAPH DB

      • Overview
      • GSQL Query Language
      • Compare Editions

      GRAPH DATA SCIENCE

      • Graph Data Science Library
      • Machine Learning Workbench
  • Solutions
    • The World’s Fastest and Most Scalable Graph Platform

      LEARN MORE

      Watch a TigerGraph Demo

      Solutions

      • Solutions Overview

      INCREASE REVENUE

      • Customer Journey/360
      • Product Marketing
      • Entity Resolution
      • Recommendation Engine

      MANAGE RISK

      • Fraud Detection
      • Anti-Money Laundering
      • Threat Detection
      • Risk Monitoring

      IMPROVE OPERATIONS

      • Supply Chain Analysis
      • Energy Management
      • Network Optimization

      By Industry

      • Advertising, Media & Entertainment
      • Financial Services
      • Healthcare & Life Sciences

      FOUNDATIONAL

      • AI & Machine Learning
      • Time Series Analysis
      • Geospatial Analysis
  • Customers
    • The World’s Fastest and Most Scalable Graph Platform

      LEARN MORE

      CUSTOMER SUCCESS STORIES

      • Ford
      • Intuit
      • JPMorgan Chase
      • READ MORE SUCCESS STORIES
      • Jaguar Land Rover
      • United Health Group
      • Xbox
  • Partners
    • The World’s Fastest and Most Scalable Graph Platform

      LEARN MORE

      PARTNER PROGRAM

      • Partner Benefits
      • TigerGraph Partners
      • Sign Up
      TigerGraph partners with organizations that offer complementary technology solutions and services.​
  • Resources
    • The World’s Fastest and Most Scalable Graph Platform

      LEARN MORE

      BLOG

      • TigerGraph Blog

      RESOURCES

      • Resource Library
      • Benchmarks
      • Demos
      • O'Reilly Graph + ML Book

      EVENTS & WEBINARS

      • Graph+AI Summit
      • Graph for All - Million Dollar Challenge
      • Events &Trade Shows
      • Webinars

      DEVELOPERS

      • Documentation
      • Ecosystem
      • Developers Hub
      • Community Forum

      SUPPORT

      • Contact Support
      • Production Guidelines

      EDUCATION

      • Training & Certifications
  • Company
    • Join the World’s Fastest and Most Scalable Graph Platform

      WE ARE HIRING

      COMPANY

      • Company Overview
      • Leadership
      • Legal Terms
      • Patents
      • Security and Compliance

      CAREERS

      • Join Us
      • Open Positions

      AWARDS

      • Awards and Recognition
      • Leader in Forrester Wave
      • Gartner Research

      PRESS RELEASE

      • Read All Press Releases
      TigerGraph Recognized in 2022 Gartner® Critical Capabilities for Cloud Database Management Systems for Analytical Use Cases
      January 12, 2023
      Read More »

      NEWS

      • Read All News

      A Shock to the System: ShockNet Predicts How Economic Shocks Could Affect the World Economy

      TigerGraph Recognized for the First Time in the 2022 Gartner® Magic Quadrant™ for Cloud Database Management Systems

  • START FREE
    • The World’s Fastest and Most Scalable Graph Platform

      GET STARTED

      • Request a Demo
      • CONTACT US
      • Try TigerGraph
      • START FREE
      • TRY AN ONLINE DEMO

Designing Feed Relationships with Graph Databases (Full Stack TigerGraph Part 2)

  • Emily McAuliffe
  • June 7, 2020
  • Developers
  • Blog >
  • Designing Feed Relationships with Graph Databases (Full Stack TigerGraph Part 2)

This article is Part 2 of a series of articles on integrating or using TigerGraph in a Full Stack application. Read Part 1 here: https://medium.com/@ramapitchala/full-stack-tigergraph-part-1-d70718111051. Follow the Author on LinkedIn and Medium.

Introduction

In my previous article (Part 1), I introduced how one can integrate TigerGraph into a Full Stack application using a web server which handles the client requests.

In this article, I will mention one use case of TigerGraph when it comes to storing interactions such as likes or comments in a Blog/Post.

I understand that there may be multiple ways of creating a blog and storing the data that may be more optimal. I simply want to showcase how it can be done, since I am using this same model in my own project.

Suppose in a small application there are entities User, Post, and Comment. These following entities can interact with each other in several ways. For example, a User can create a Post, a User can like a Post, User can comment and a User can like a Comment. In addition, Post and Comment can also have child comments. Suppose these interactions are thought of as Vertices with Edges.

It is intuitive how Graph databases can represent these relationships. If you want to follow along, now is the time to create a TigerGraph Cloud Instance as well as a web server to interact with and model this data. You can easily walk through Part 1 and learn how to create both the TigerGraph Cloud Instance and the NodeJS + Express web server.

Disclaimer: Although you are free to add fields as you see fit, I will not be storing the actual content of the Posts or Comments in TigerGraph. In the project that I mentioned earlier, I am actually storing the Comment and Post data in Cloud Firestore. We are using TigerGraph to store the relationships between Posts, Comments and Users.

Our vertices will look as follows:

Post:

Comment:

The comments attribute serves as an aggregator on the vertices. Suppose we need information about the child comments on both the Post and Comment vertex in the metadata. Depending on the scale, it would be more efficient to store an aggregator and use it to find the information about the number of child comments. However, we must increment comments of the parent by 1 whenever a new child comment is created.

User:

I did not place any attributes on the edges for now. You are free to add attributes that are beneficial to your case. Now that we have our schema ready to go, let’s save our changes and move onto writing the queries.

Let’s write a query to create a new post based on the incoming post id (post) and by the author (user). Let’s also do the same for comments. If a new comment is created as either a response to a Post (createCommentsOnPost) or as a response to a Comment(createReplyToComment), we must increment the attribute comments of the parent by 1.

CREATE QUERY createPost(Vertex<User> user, String post) FOR GRAPH MyGraph { 
  Insert Into Post(PRIMARY_ID, comments) Values(post, 0);
  Insert Into CREATES_POST(From, To) Values(user User, post Post);
}
CREATE QUERY createCommentOnPost(Vertex<User> user, Vertex<Post> parent, String comment) FOR GRAPH MyGraph { 
  parent.comments = parent.comments + 1;
  Insert Into Comment(PRIMARY_ID, comments) Values(comment, 0);
  Insert Into IS_CHILD_OF_POST(From, To) Values(comment Comment,      parent Post);
  Insert Into CREATES_COMMENT(From, To) Values(user User, comment Comment);
}
CREATE QUERY createReplyOnComment(Vertex<User> user, Vertex<Comment> parent, String comment) FOR GRAPH MyGraph { 
  parent.comments = parent.comments + 1;
  Insert Into Comment(PRIMARY_ID, comments) Values(comment, 0);
  Insert Into IS_CHILD_OF_COMMENT(From, To) Values(comment Comment, parent Comment);
  Insert Into CREATES_COMMENT(From, To) Values(user User, comment Comment);
}

Now, let’s write some queries to handle liking and unliking Posts and Comments.

CREATE QUERY toggleLikesOnComment(Vertex<Comment> comment, Vertex<User> user, String action) FOR GRAPH MyGraph { 
  if action == "LIKE" then
   Insert Into LIKES_COMMENT(From, To) Values(user User, comment   Comment);
  else
   Start = {comment};
   p = Select s from Start:s -(LIKES_COMMENT:e)-> User:tgt
       Where tgt.id == user.id
       Accum delete(e);
 end;
}
CREATE QUERY toggleLikesOnPost(Vertex<Post> post, Vertex<User> user, String action) FOR GRAPH MyGraph { 
  if action == "LIKE" then
   Insert Into LIKES_POST(From, To) Values(user User, post Post);
 else
   Start = {post};
   p = Select s from Start:s -(LIKES_POST:e)-> User:tgt
       Where tgt.id == user.id
       Accum delete(e);
 end;
}

Finally, we need to write the queries that provide clients with metadata for the Posts and Comments. For posts, the query takes in a set of Post ids as a parameter. In response, the query prints metadata information such as the number of child comments on a Post and an array of ids of all the Users who like the Post. The same is replicated for the Comments.

CREATE QUERY getPostMetadata(Set<Vertex<Post>> posts) FOR GRAPH MyGraph { 
  SetAccum<String> @likers;
  start = posts;
 pos = Select s From start:s -(LIKES_POST)-> User:tgt
           Accum [email protected] += tgt.id;
 
 Print pos as Posts;
}
CREATE QUERY getCommentMetadata(Set<Vertex<Comment>> comments) FOR GRAPH MyGraph { 
 SetAccum<String> @likers;
  start = comments;
 com = Select s From start:s -(LIKES_COMMENT)-> User:tgt
           Accum [email protected] += tgt.id;
 
 Print com as Comments;
}

Now, that we have our queries, let’s now focus on setting up our Web server. The Execution section of Part 1 navigates through this process. On this project, however, there are many more endpoints to write.

The config file in my directory contains an object with the TigerGraph cloud instance url and the token.

const express = require("express");
const app = express();
const config = require("./config");


app.use(express.json()); 

/*
All the parameters to the endpoints below will simply be passed as a object in the body.
This is easily customizable.
*/
app.get("/comments", async (req, res)=>{
    try{
        let body = req.body;
        let url = config.url + "getCommentMetadata";
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }
    catch(error){
        handleError(res, error.message);
    }
});

app.get("/posts", async (req, res) => {
    try{
        let body = req.body;
        let url = config.url + "getPostMetadata";
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }   
    catch(error){
        handleError(res, error.message);
    }
});

app.post("/toggle-like-post", async (req, res) => {
    try{
        let body = req.body;
        let url = config.url + "toggleLikesOnPost";
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }
    catch(error){
        handleError(res, error.message);
    }
});

app.post("/toggle-like-comment", async (req, res) =>{
    try{
        let body = req.body;
        let url = config.url + "toggleLikesOnComment";
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }
    catch(error){
        handleError(res, error.message);
    }
});

app.post("/create-child", async (req, res) => {
    try{    
        let body = req.body;
        let url = config.url;
        if("post" in body){
            url += "createCommentOnPost";
        }
        else{
            url += "createReplyOnComment";
        }
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }   
    catch(error){
        handleError(res, error.message);
    }
});

app.post("/create-post", async (req, res)=>{
    try{
        let body = req.body;
        let url = config.url + "createPost";
        let response = await _makeCall(url, body);
        res.status(200).send(response);
    }
    catch(error){
        handleError(res, error.message);
    }

});

/*
This is where the magic happens. Each of the end points will pass in a query url
with an object of parameters. This function will construct the url and make the call.
*/
async function _makeCall(url, params){
    try{
        const keys = Object.keys(params);
        if (keys.length > 0) {
          url += "?"
          for (let index = 0; index < keys.length; index++) {
            const key = keys[index];
            if (Array.isArray(params[key])) { //It was an array of values
              let heading = `${key}=`;
              if (index > 0) {
                heading = `&${key}=`;
              }
              url += heading;
              url += (params[key]).join(`&${key}=`);
            } else { //It was just a single value
              if (index === 0) {
                url += key + "=" + params[key]
              } else {
                url += "&" + key + "=" + params[key]
              }
            }
          }
        }
        const token = config.token;
        const response = await fetch(url, {
                method: 'GET',
                headers: {
                    'Authorization': 'Bearer ' + token,
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                }
        });
        const json = await response.json();
        if(json.error){
            throw Error("TigerGraphError:" + json.message);
        }
        return json;  
    }
    catch(error){
        throw Error(error.message);
    }
}

function handleError(res, errorMessage){
    if(errorMessage.indexOf("TigerGraphError") > 0){
        res.status(500).send({error:true, message:errorMessage})
    }
    else{
        res.status(400).send({error:true, message:errorMessage})
    }
}

Here are examples on how calling the endpoints would look like on the JavaScript client side:

import fetch from "node-fetch";


const url = "http://localhost:5000/"

function getComments(commentIds){
    let requestUrl = url + "comments";
    let response = await fetch(requestUrl, 
        {
            body: JSON.stringify(
                {comments: commentIds}
            )
        });
    let json = await response.json();
    if(json.error){
        throw Error("Failed to retrieve the comments");
    }
    return json;
}

function getPosts(postIds){
    let requestUrl = url + "posts";
    let response = await fetch(requestUrl, 
        {
            body: JSON.stringify(
                {posts: postIds}
            )
        });
    let json = await response.json();
    if(json.error){
        throw Error("Failed to retrieve the posts");
    }
    return json;
}

function toggleLikeOnPost(post, user, action){
        let requestUrl = url + "toggle-like-post";
        let response = await fetch(requestUrl, 
            {
                method: "POST",
                body: JSON.stringify(
                    {post: post, user:user, action:action}
                )
            });
        let json = await response.json();
        if(json.error){
            throw Error("Failed to toggle like on post");
        }
        return json;
}

function toggleLikeOnComment(comment, user, action){
    let requestUrl = url + "toggle-like-comment";
    let response = await fetch(requestUrl, 
        {
            method: "POST",
            body: JSON.stringify(
                {comment: comment, user:user, action:action}
            )
        });
    let json = await response.json();
    if(json.error){
        throw Error("Failed to toggle like on comment");
    }
    return json;
}

function createPost(user, post){
    let requestUrl = url + "create-post";
    let response = await fetch(requestUrl, 
        {
            method:"POST",
            body: JSON.stringify(
                {user:user, post:post}
            )
        });
    let json = await response.json();
    if(json.error){
        throw Error("Failed to create post");
    }
    return json;
}

function createChild(user, parent, comment, type){
    let requestUrl = url + "create-child";
    let response = await fetch(requestUrl, 
        {
            method: "POST",
            body: JSON.stringify(
                {user:user, parent:parent, comment:comment,type:type.toUpperCase()}
            )
        });
    let json = await response.json();
    if(json.error){
        throw Error("Failed to create comment");
    }
    return json;
}

These end points do not have to be limited to just making calls to TigerGraph. In fact, one of the benefits with the approach of having a web server to handle client requests is that multiple services can converge, abstracted from the client. For example, perhaps in the /create-post endpoint, I could insert in a new Post document in Firestore, or I could the use Twilio Api to notify a user if they were mentioned in the Post.

Disadvantages

Maintenance: If a new TigerGraph instance is spun up, then an another database must be maintained.In my case, calls must be made to both Firestore when retrieving comments or posts, creating comments or posts as well deleting.

Advantages

Insights: The core relationship data between the entities will already be stored on the Graph itself, making various algorithms for perhaps finding Community groups between users or Influencers readily available.

Conclusion

More edges, vertices, and attributes can be added to schema to improve its design. What I have showed you today is simply a starting point. Please let me know if you liked or disliked some part of the article and how I can improve. Thank you very much for reading!

You Might Also Like

Developer Spotlight: Kapil Saini

Developer Spotlight: Kapil Saini

October 21, 2022
Graph Neural Network-based Graph Outlier Detection: A Brief Introduction

Graph Neural Network-based Graph Outlier Detection:...

September 15, 2022
Developer Spotlight: Renata Bastos Gottgtroy

Developer Spotlight: Renata Bastos Gottgtroy

September 12, 2022

Introducing TigerGraph 3.0

July 1, 2020

Everything to Know to Pass your TigerGraph Certification Test

June 24, 2020

Neo4j 4.0 Fabric – A Look Behind the Curtain

February 7, 2020

TigerGraph Blog

  • Categories
    • blogs
      • About TigerGraph
      • Benchmark
      • Business
      • Community
      • Compliance
      • Customer
      • Customer 360
      • Cybersecurity
      • Developers
      • Digital Twin
      • eCommerce
      • Emerging Use Cases
      • Entity Resolution
      • Finance
      • Fraud / Anti-Money Laundering
      • GQL
      • Graph Database Market
      • Graph Databases
      • GSQL
      • Healthcare
      • Machine Learning / AI
      • Podcast
      • Supply Chain
      • TigerGraph
      • TigerGraph Cloud
    • Graph AI On Demand
      • Analysts and Research
      • Customer 360 and Entity Resolution
      • Customer Spotlight
      • Development
      • Finance, Banking, Insurance
      • Keynote
      • Session
    • Video
  • Recent Posts

    • It’s Time to Harness the Power of Graph Technology [Infographic]
    • TigerGraph Showcases Unrivaled Performance at Scale
    • TigerGraph 101 An Introduction to Graph | Jan 26th @ 9am PST
    • Data Science Salon New York
    • Tech For Retail
    TigerGraph

    Product

    SOLUTIONS

    customers

    RESOURCES

    start for free

    TIGERGRAPH DB
    • Overview
    • Features
    • GSQL Query Language
    GRAPH DATA SCIENCE
    • Graph Data Science Library
    • Machine Learning Workbench
    TIGERGRAPH CLOUD
    • Overview
    • Cloud Starter Kits
    • Login
    • FAQ
    • Pricing
    • Cloud Marketplaces
    USEr TOOLS
    • GraphStudio
    • TigerGraph Insights
    • Application Workbenches
    • Connectors and Drivers
    • Starter Kits
    • openCypher Support
    SOLUTIONS
    • Why Graph?
    industry
    • Advertising, Media & Entertainment
    • Financial Services
    • Healthcare & Life Sciences
    use cases
    • Benefits
    • Product & Service Marketing
    • Entity Resolution
    • Customer 360/MDM
    • Recommendation Engine
    • Anti-Money Laundering
    • Cybersecurity Threat Detection
    • Fraud Detection
    • Risk Assessment & Monitoring
    • Energy Management
    • Network & IT Management
    • Supply Chain Analysis
    • AI & Machine Learning
    • Geospatial Analysis
    • Time Series Analysis
    success stories
    • Customer Success Stories

    Partners

    Partner program
    • Partner Benefits
    • TigerGraph Partners
    • Sign Up
    LIBRARY
    • Resources
    • Benchmark
    • Webinars
    Events
    • Trade Shows
    • Graph + AI Summit
    • Million Dollar Challenge
    EDUCATION
    • Training & Certifications
    Blog
    • TigerGraph Blog
    DEVELOPERS
    • Developers Hub
    • Community Forum
    • Documentation
    • Ecosystem

    COMPANY

    Company
    • Overview
    • Careers
    • News
    • Press Release
    • Awards
    • Legal
    • Patents
    • Security and Compliance
    • Contact
    Get Started
    • Start Free
    • Compare Editions
    • Online Demo - Test Drive
    • Request a Demo

    Product

    • Overview
    • TigerGraph 3.0
    • TIGERGRAPH DB
    • TIGERGRAPH CLOUD
    • GRAPHSTUDIO
    • TRY NOW

    customers

    • success stories

    RESOURCES

    • LIBRARY
    • Events
    • EDUCATION
    • BLOG
    • DEVELOPERS

    SOLUTIONS

    • SOLUTIONS
    • use cases
    • industry

    Partners

    • partner program

    company

    • Overview
    • news
    • Press Release
    • Awards

    start for free

    • Request Demo
    • take a test drive
    • SUPPORT
    • COMMUNITY
    • CONTACT
    • Copyright © 2023 TigerGraph
    • Privacy Policy
    • Linkedin
    • Facebook
    • Twitter

    Copyright © 2020 TigerGraph | Privacy Policy

    Copyright © 2020 TigerGraph Privacy Policy

    • SUPPORT
    • COMMUNITY
    • COMPANY
    • CONTACT
    • Linkedin
    • Facebook
    • Twitter

    Copyright © 2020 TigerGraph

    Privacy Policy

    • Products
    • Solutions
    • Customers
    • Partners
    • Resources
    • Company
    • START FREE
    START FOR FREE
    START FOR FREE
    TigerGraph
    PRODUCT
    PRODUCT
    • Overview
    • GraphStudio UI
    • Graph Data Science Library
    TIGERGRAPH DB
    • Overview
    • Features
    • GSQL Query Language
    TIGERGRAPH CLOUD
    • Overview
    • Cloud Starter Kits
    TRY TIGERGRAPH
    • Get Started for Free
    • Compare Editions
    SOLUTIONS
    SOLUTIONS
    • Why Graph?
    use cases
    • Benefits
    • Product & Service Marketing
    • Entity Resolution
    • Customer Journey/360
    • Recommendation Engine
    • Anti-Money Laundering (AML)
    • Cybersecurity Threat Detection
    • Fraud Detection
    • Risk Assessment & Monitoring
    • Energy Management
    • Network Resources Optimization
    • Supply Chain Analysis
    • AI & Machine Learning
    • Geospatial Analysis
    • Time Series Analysis
    industry
    • Advertising, Media & Entertainment
    • Financial Services
    • Healthcare & Life Sciences
    CUSTOMERS
    read all success stories

     

    PARTNERS
    Partner program
    • Partner Benefits
    • TigerGraph Partners
    • Sign Up
    RESOURCES
    LIBRARY
    • Resource Library
    • Benchmark
    • Webinars
    Events
    • Trade Shows
    • Graph + AI Summit
    • Graph for All - Million Dollar Challenge
    EDUCATION
    • TigerGraph Academy
    • Certification
    Blog
    • TigerGraph Blog
    DEVELOPERS
    • Developers Hub
    • Community Forum
    • Documentation
    • Ecosystem
    COMPANY
    COMPANY
    • Overview
    • Leadership
    • Careers  
    NEWS
    PRESS RELEASE
    AWARDS
    START FREE
    Start Free
    • Request a Demo
    • SUPPORT
    • COMMUNITY
    • CONTACT
    Dr. Jay Yu

    Dr. Jay Yu | VP of Product and Innovation

    Dr. Jay Yu is the VP of Product and Innovation at TigerGraph, responsible for driving product strategy and roadmap, as well as fostering innovation in graph database engine and graph solutions. He is a proven hands-on full-stack innovator, strategic thinker, leader, and evangelist for new technology and product, with 25+ years of industry experience ranging from highly scalable distributed database engine company (Teradata), B2B e-commerce services startup, to consumer-facing financial applications company (Intuit). He received his PhD from the University of Wisconsin - Madison, where he specialized in large scale parallel database systems

    Todd Blaschka | COO

    Todd Blaschka is a veteran in the enterprise software industry. He is passionate about creating entirely new segments in data, analytics and AI, with the distinction of establishing graph analytics as a Gartner Top 10 Data & Analytics trend two years in a row. By fervently focusing on critical industry and customer challenges, the companies under Todd's leadership have delivered significant quantifiable results to the largest brands in the world through channel and solution sales approach. Prior to TigerGraph, Todd led go to market and customer experience functions at Clustrix (acquired by MariaDB), Dataguise and IBM.