AvatoLabs GraghDB Course Part II

Marlon ShelbyMarlon Shelby
16 min read

Chapter 2: Introduction to Cypher Language

2.1 Introduction to Cypher Language

Cypher is Neo4j's specialized query language, adopting a declarative structure designed specifically for processing graph data. Its syntax is easy to understand and intuitively reflects the structure of graphs, using ASCII art to represent patterns of nodes and relationships.

2.1.1 Cypher Design Philosophy

  • Declarative: Specifies "what you want" rather than "how to do it"

  • Pattern matching: Uses visually intuitive syntax to describe graph patterns

  • Human-friendly: Designed to be easy to read and write, similar to natural language

  • Concise and powerful: Complex graph operations can be expressed with brief statements

2.1.2 Basic Syntax Structure

Cypher queries typically follow this structure:

  1. START: Specifies starting points (usually replaced by MATCH in modern Cypher)

  2. MATCH: Defines graph patterns to match

  3. WHERE: Specifies filtering conditions

  4. RETURN: Specifies the result set to return

  5. ORDER BY, SKIP, LIMIT: Result sorting and pagination

  6. CREATE, DELETE, SET, REMOVE: Data modification operations

2.2 Basic Retrieval Operations

2.2.1 MATCH Clause

The MATCH clause is the core of Cypher, used to define patterns to match in the graph. Syntax example:

MATCH (n:Person)
RETURN n

This query matches all nodes with the Person label and returns them. Graphical pattern syntax:

  • Nodes represented with parentheses: ()

  • Labels represented with colons: (n:Person)

  • Relationships represented with brackets and arrows: -[r:KNOWS]->

  • Properties represented with braces: (n:Person {name: 'Alice'})

Avato Chat case: Finding all users and who they follow

MATCH (user:User)-[:FOLLOWS]->(followee:User)
RETURN user.username AS Follower, followee.username AS Followee

This query shows the following relationships between users in the Avato Chat social network, helping build social graphs and implement personalized content recommendations.

OPTIONAL MATCH is a powerful feature in Cypher, similar to LEFT OUTER JOIN in SQL. It allows matching patterns that may not exist without filtering out results when the pattern doesn't match.

2.2.2 OPTIONAL MATCH Basics

The basic syntax for OPTIONAL MATCH is as follows:

MATCH (u:User {username: 'alice'})
OPTIONAL MATCH (u)-[:POSTED]->(p:Post)
RETURN u.username, p.content

This query will return alice's username and the content of any posts she might have published. If alice hasn't published any posts, the query will still return alice's username, but the post content field will be NULL.

2.2.2.1 Handling NULL Values

When OPTIONAL MATCH doesn't match any results, related variables are set to NULL:

MATCH (u:User {username: 'alice'})
OPTIONAL MATCH (u)-[:POSTED]->(p:Post)
RETURN u.username, p.content, 
       CASE WHEN p IS NULL THEN 'No posts yet' ELSE 'Has posts' END AS PostStatus

You can use CASE statements or other conditional logic to handle NULL values, providing default values or status information.

2.2.2.2 Multi-condition OPTIONAL MATCH

You can use multiple OPTIONAL MATCH clauses to retrieve different types of optional relationships:

MATCH (u:User {username: 'alice'})
OPTIONAL MATCH (u)-[:POSTED]->(p:Post)
OPTIONAL MATCH (u)-[:COMMENTED]->(c:Comment)
OPTIONAL MATCH (u)-[:LIKED]->(l:Post)
RETURN u.username, 
       count(DISTINCT p) AS PostCount, 
       count(DISTINCT c) AS CommentCount,
       count(DISTINCT l) AS LikeCount

This query calculates the number of posts, comments, and likes from alice, even if some of these relationships don't exist.

2.2.2.3 Combining OPTIONAL MATCH with WHERE Clauses

You can add conditions to OPTIONAL MATCH using WHERE clauses:

MATCH (u:User)
OPTIONAL MATCH (u)-[:POSTED]->(p:Post)
WHERE p.createdAt > datetime() - duration('P30D') // Only match posts from the last 30 days
RETURN u.username, count(p) AS RecentPostCount

This query counts the number of posts made by each user in the last 30 days, with users who haven't posted having a RecentPostCount of 0.

2.2.2.4 WHERE Clause

The WHERE clause is used to filter results returned by MATCH. Syntax example:

MATCH (n:Person)
WHERE n.age > 30
RETURN n.name, n.age

Common operators:

OperatorDescriptionExample
\=Equal toWHERE n.age = 30
<>Not equal toWHERE n.name <> 'Bob'
\>Greater thanWHERE n.age > 30
\>=Greater than or equal toWHERE n.salary >= 5000
<Less thanWHERE n.price < 100
<=Less than or equal toWHERE n.score <= 9.5
IS NULLNULL checkWHERE n.phone IS NULL
IS NOT NULLNon-NULL checkWHERE n.email IS NOT NULL

Boolean operators:

OperatorDescriptionExample
ANDLogical ANDWHERE n.age > 20 AND n.age < 30
ORLogical ORWHERE n.city = 'Beijing' OR n.city = 'Shanghai'
NOTLogical NOTWHERE NOT n.inactive
XORLogical XORWHERE n.admin XOR n.moderator

Dual-track MLM Case: Finding users who meet collision conditions

MATCH (u:User)
WHERE u.direct_impact = 0 AND u.relative_impact = 0
  AND datetime(u.joinDate) > datetime() - duration('P30D')
RETURN u.id, u.name, u.joinDate, u.direct_father, u.tree_father
ORDER BY u.joinDate ASC

This query helps the dual-track collision system identify newly joined users who haven't experienced any collisions yet, facilitating collision calculations and reward distribution. According to the Korean collision mechanism, each node needs to be identified if it has two unused collision life values.

2.2.4 RETURN Clause

The RETURN clause specifies the result set that the query should return. Syntax example:

MATCH (n:Person)
RETURN n.name, n.age, n.email

Return options:

  • Return entire node: RETURN n

  • Return specific properties: RETURN n.name, n.age

  • Use aliases: RETURN n.name AS Name, n.age AS Age

  • Return calculation results: RETURN n.firstName + ' ' + n.lastName AS FullName

  • Distinct values: RETURN DISTINCT n.city

RGB Protocol Case: Return digital asset holdings sorted by value

MATCH (w:Wallet)-[:HOLDS]->(a:Asset)
RETURN w.address AS WalletAddress, a.symbol AS AssetSymbol, 
       a.quantity AS Quantity, a.quantity * a.price AS TotalValue
ORDER BY TotalValue DESC

This query in the RGB protocol Bitcoin ecosystem can quickly summarize asset holdings across wallets, facilitating asset analysis and value assessment.

2.2.5 ORDER BY, SKIP, LIMIT Clauses

These clauses are used for sorting and paginating query results. ORDER BY: Sort results

MATCH (n:Product)
RETURN n.name, n.price
ORDER BY n.price DESC

SKIP: Skip a specified number of results

MATCH (n:Movie)
RETURN n.title, n.year
ORDER BY n.year
SKIP 10

LIMIT: Limit the number of returned results

MATCH (n:Book)
RETURN n.title, n.author
LIMIT 5

Avato Chat Case: Implementing paginated message queries (20 messages per page, querying page 2)

MATCH (u:User {username: 'alice'})-[:SENT]->(m:Message)-[:IN_CHAT]->(c:Chat {id: 'chat123'})
RETURN m.content, m.sentTime, m.readStatus
ORDER BY m.sentTime DESC
SKIP 20
LIMIT 20

This query implements paginated loading of chat history in Avato Chat, improving performance when querying large numbers of messages and enhancing user experience.

2.3 Advanced Retrieval Features

2.3.1 Path Queries

Cypher can query paths between nodes, which is one of the powerful features of graph databases. Variable-length paths: Use * to specify path length

// Find friend relationships 1 to 3 hops away
MATCH (a:Person {name: 'Alice'})-[:FRIEND*1..3]->(b:Person)
RETURN b.name

Shortest path: Use the shortestPath function

MATCH p = shortestPath((a:Person {name: 'Alice'})-[*]-(b:Person {name: 'Bob'}))
RETURN p, length(p) AS pathLength

Avato Chat Case: Finding social distance between users

MATCH p = shortestPath((user1:User {username: 'alice'})-[:FOLLOWS|:FRIEND_OF*]-(user2:User {username: 'bob'}))
RETURN length(p) AS SocialDistance, 
       [node in nodes(p) | node.username] AS ConnectionPath

This query is crucial for the Avato Chat social network, as it calculates the social distance between users, used for "mutual friends" recommendations, user relationship chain analysis, and community discovery.

2.3.2 Aggregate Functions

Cypher provides various collection functions for aggregate calculations. Common collection functions:

FunctionDescriptionExample
count()CountRETURN count(n)
sum()SumRETURN sum(n.value)
avg()AverageRETURN avg(n.score)
min()MinimumRETURN min(n.age)
max()MaximumRETURN max(n.price)
collect()Collect values into a listRETURN collect(n.name)

Group aggregation: Use WITH clause for grouping

MATCH (u:User)-[:PURCHASED]->(p:Product)
WITH u, count(p) AS purchaseCount
WHERE purchaseCount > 5
RETURN u.name, purchaseCount
ORDER BY purchaseCount DESC

Dual-track MLM Case: Calculate average sales and user count for each user level

MATCH (u:User)
WITH u.level AS Level, count(u) AS UserCount, avg(u.salesVolume) AS AvgSales
RETURN Level, UserCount, AvgSales, AvgSales/UserCount AS Efficiency
ORDER BY AvgSales DESC

This query allows the dual-track MLM system to evaluate the performance of users at different levels, helping formulate more precise incentive policies and performance targets. In the collision system, each person is an independent user with the opportunity to develop and expand their own network.

2.3.3 Data Filtering and Pattern Matching

Cypher provides various string matching and filtering capabilities. STARTS WITH: Prefix matching

MATCH (n:Person)
WHERE n.name STARTS WITH 'A'
RETURN n.name

ENDS WITH: Suffix matching

MATCH (n:Person)
WHERE n.email ENDS WITH '@gmail.com'
RETURN n.name, n.email

CONTAINS: Substring matching

MATCH (n:Product)
WHERE n.description CONTAINS 'waterproof'
RETURN n.name, n.description

Regular expressions: Use the =~ operator

MATCH (n:Person)
WHERE n.phone =~ '\\+86.*'
RETURN n.name, n.phone

RGB Protocol Case: Finding transactions of specific types or statuses

MATCH (tx:Transaction)
WHERE tx.type CONTAINS 'RGB' OR tx.status CONTAINS 'pending'
RETURN tx.txid, tx.type, tx.amount, tx.status, tx.timestamp
ORDER BY tx.timestamp DESC

This query can be used in the RGB protocol ecosystem to monitor and analyze specific types of transactions, such as retrieving all RGB protocol-related or pending transactions, facilitating tracking and troubleshooting.

2.4 Data Modification Operations

2.4.1 CREATE Statement

CREATE is used to create new nodes and relationships. Creating nodes:

CREATE (n:Person {name: 'Charlie', age: 35, email: 'charlie@example.com'})

Creating multiple nodes:

CREATE (a:Person {name: 'Alice', age: 28}),
       (b:Person {name: 'Bob', age: 32})

Creating relationships:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
CREATE (a)-[:KNOWS {since: 2020}]->(b)

Avato Chat Case: Creating groups, messages, and sending relationships

CREATE (g:Group {id: 'g10001', name: 'Tech Discussion Group', createdAt: datetime()}),
       (u:User {id: 'u2345', username: 'alex_dev', joinDate: date()}),
       (m:Message {id: 'm9876', content: 'Hello everyone, I am a new developer', sentAt: datetime()}),
       (u)-[:MEMBER_OF {joinedAt: datetime(), role: 'member'}]->(g),
       (u)-[:SENT {device: 'iPhone', location: 'Beijing'}]->(m),
       (m)-[:POSTED_IN]->(g)

This query demonstrates how to create a complete group communication data structure in Avato Chat, including groups, users, messages, and their relationships, with rich metadata.

2.4.2 MERGE Statement

MERGE is used to conditionally create data and can be viewed as "create if it doesn't exist, match if it does." Node MERGE:

MERGE (n:Person {name: 'Dave'})
ON CREATE SET n.created = timestamp()
ON MATCH SET n.lastSeen = timestamp()

Relationship MERGE:

MATCH (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'})
MERGE (a)-[r:KNOWS]-(b)
RETURN a, r, b

Dual-track Collision MLM Case: Ensuring the correct establishment of user binary tree structure

MERGE (parent:User {id: 'U1001'})
ON CREATE SET parent.name = 'Zhang San', parent.joinDate = date()
WITH parent
MATCH (newUser:User {id: 'U2002'})
// Check if parent node has an open position
OPTIONAL MATCH (parent) 
WHERE parent.left_child = 0 OR parent.right_child = 0
WITH parent, newUser, 
     CASE WHEN parent.left_child = 0 THEN 'left' 
          WHEN parent.right_child = 0 THEN 'right'
          ELSE null END AS availableSide
// If there's an open position, establish a direct parent-child relationship
FOREACH(side IN CASE WHEN availableSide = 'left' THEN [1] ELSE [] END |
  MERGE (parent)-[r:LEFT_CHILD]->(newUser)
  SET parent.left_child = toInteger(newUser.id)
)
FOREACH(side IN CASE WHEN availableSide = 'right' THEN [1] ELSE [] END |
  MERGE (parent)-[r:RIGHT_CHILD]->(newUser)
  SET parent.right_child = toInteger(newUser.id)
)
// Set tree structure information
SET newUser.tree_father = toInteger(parent.id)

This query ensures the correct establishment of the binary tree structure of users in the dual-track collision system, placing new users based on the availability of left and right child nodes. Based on the Korean collision reward 2.0 mechanism, maintaining the correct binary tree structure is crucial for collision calculations, where each node has only one direct left subordinate and one right subordinate.

2.4.3 SET Statement

SET is used to update properties and labels. Update a single property:

MATCH (n:Person {name: 'Alice'})
SET n.age = 29

Update multiple properties:

MATCH (n:Person {name: 'Bob'})
SET n.job = 'Developer', n.updated = timestamp()

Update using property mapping:

MATCH (n:Person {name: 'Charlie'})
SET n += {age: 36, job: 'Designer', updated: timestamp()}

Add a label:

MATCH (n:Person {name: 'Dave'})
SET n:Employee

RGB Protocol Case: Update asset price and last trade information

MATCH (a:Asset {symbol: 'RGB-20-USDT'})
SET a.price = 1.002,
    a.lastTraded = datetime(),
    a.volume24h = coalesce(a.volume24h, 0) + 50000,
    a.updateCount = coalesce(a.updateCount, 0) + 1

This query is used for updating digital asset prices in the RGB protocol ecosystem, which is a key operation for asset tracking and market analysis.

2.4.4 REMOVE Statement

REMOVE is used to delete properties and labels. Delete a property:

MATCH (n:Person {name: 'Alice'})
REMOVE n.age

Remove a label:

MATCH (n:Person {name: 'Bob'})
REMOVE n:Employee

Avato Chat Case: Remove temporary status markers from users

MATCH (u:User)
WHERE u.lastActive < datetime() - duration('P30D')
REMOVE u:Online
SET u:Inactive
SET u.inactiveDate = date()

This query is used in Avato Chat to manage user online status, marking users who have been inactive for 30 days as inactive, which is useful for subsequent user retention analysis and activation strategies.

2.4.5 DELETE Statement

DELETE is used to delete nodes and relationships. Delete a relationship:

MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
DELETE r

Delete a node:

MATCH (n:Person {name: 'Charlie'})
DETACH DELETE n  // DETACH deletes the node and all its relationships

Avato Chat Case: Clean up expired messages and notifications

// Delete relationships for temporary messages older than 90 days, but keep message content for compliance records
MATCH (m:Message {type: 'Temporary'})<-[r:RECEIVED]-(u:User)
WHERE m.sendTime < datetime() - duration('P90D')
DELETE r

// Clean up read notification relationships, keeping notification nodes for system analysis
MATCH (u:User)-[r:HAS_NOTIFICATION {status: 'Read'}]->(n:Notification)
WHERE n.createdAt < datetime() - duration('P30D')
DELETE r
WITH n
// If the notification is no longer connected to any user, add an archive label but don't delete the node
WHERE NOT EXISTS { MATCH (n)<-[:HAS_NOTIFICATION]-() }
SET n:Archived
REMOVE n:Active

This query is used in the Avato Chat platform to clean up expired temporary message relationships and read notification relationships, while preserving basic message and notification data to maintain chat history integrity and compliance requirements. Similar to the dual-track collision system, Avato Chat also retains complete historical records, only deleting relationships without deleting core nodes.

2.5 Advanced Data Operations

2.5.1 WITH Clause

The WITH clause serves as an intermediate result in queries, allowing results from one part of a query to be passed to the next part. Basic usage:

MATCH (a:Person)-[:WORKS_AT]->(c:Company)
WITH a.name AS EmployeeName, c.name AS CompanyName
ORDER BY CompanyName, EmployeeName
RETURN CompanyName, collect(EmployeeName) AS Employees

Filtering intermediate results:

MATCH (u:User)-[:PURCHASED]->(p:Product)
WITH u, count(p) AS productCount
WHERE productCount > 5
RETURN u.name, productCount

Avato Chat Case: Finding the most active communities and their core members

MATCH (g:Group)<-[:POSTED_IN]-(m:Message)
WITH g, count(m) AS messageCount
ORDER BY messageCount DESC
LIMIT 10
MATCH (g)<-[:MEMBER_OF]-(u:User)-[:SENT]->(msg:Message)-[:POSTED_IN]->(g)
WITH g, messageCount, u, count(msg) AS userMessages
WITH g, messageCount, collect({user: u.username, messages: userMessages}) AS activeUsers
RETURN g.name AS groupName, 
       g.memberCount AS totalMembers,
       messageCount AS totalMessages, 
       activeUsers[0..5] AS topContributors

This query analyzes the most active communities in Avato Chat and their core contributing members, providing data support for community operations and user incentives.

2.5.2 UNION and UNION ALL

These operators are used to combine multiple query results. UNION: Combine and remove duplicates

MATCH (n:Actor)
RETURN n.name AS name
UNION
MATCH (n:Director)
RETURN n.name AS name

UNION ALL: Combine without removing duplicates

MATCH (n:Actor)
RETURN n.name AS name
UNION ALL
MATCH (n:Director)
RETURN n.name AS name

RGB Protocol Case: Combining query results for different types of assets

// Find RGB-20 type assets
MATCH (a:Asset)
WHERE a.protocol = 'RGB-20'
RETURN a.name AS result, 'FungibleToken' AS type, a.price AS value, a.marketCap AS relevance

UNION

// Find RGB-21 type assets
MATCH (a:Asset)
WHERE a.protocol = 'RGB-21'
RETURN a.name AS result, 'NFT' AS type, a.lastSoldPrice AS value, a.popularity AS relevance

UNION

// Find RGB-25 type assets
MATCH (a:Asset)
WHERE a.protocol = 'RGB-25'
RETURN a.name AS result, 'Covenant' AS type, a.tvl AS value, a.tvl AS relevance

// Sort by relevance
ORDER BY relevance DESC

This query combines searches for different types of assets (fungible tokens, non-fungible tokens, and covenants) in the RGB protocol ecosystem, providing users with a unified asset search view.

2.5.3 FOREACH Statement

FOREACH is used to perform update operations on each element in a collection. Basic usage:

MATCH p = (start:Person {name: 'Alice'})-[:KNOWS*1..3]->(friend)
FOREACH (n IN nodes(p) | SET n.marked = true)

Dual-track Collision MLM Case: Batch update user status

// Create a list of users to update
WITH [
  {id: 'U1001', newStatus: 'Collided', note: 'Absolute collision completed'},
  {id: 'U2002', newStatus: 'Collided', note: 'Relative collision completed'},
  {id: 'U3003', newStatus: 'Reward Processing', note: 'Pending settlement'}
] AS userStatusList
UNWIND userStatusList AS userStatus
MATCH (u:User {id: userStatus.id})
SET u.collisionStatus = userStatus.newStatus,
    u.statusNote = userStatus.note,
    u.lastUpdated = datetime()
WITH u, userStatus
// Create status change notification for user
CREATE (n:Notification {
  id: 'N' + toString(rand()*1000000), 
  content: 'Your collision status has been updated to: ' + userStatus.newStatus,
  createdAt: datetime(),
  type: 'StatusChange'
})
CREATE (u)-[:HAS_NOTIFICATION {isRead: false}]->(n)

This query is used in the dual-track collision system for batch updating users' collision status, recording status change time and reason, and creating corresponding status change notifications for users. According to the Korean collision reward 2.0 mechanism, each node has two collision life values, and this update helps track user status in absolute and relative collisions.

2.5.4 CALL Clause

CALL is used to invoke Neo4j's stored procedures and user-defined functions. Invoking built-in procedures:

CALL db.labels()
YIELD label
RETURN label

Calling graph algorithms:

CALL gds.pageRank.stream('myGraph')
YIELD nodeId, score
RETURN gds.util.asNode(nodeId).name AS name, score
ORDER BY score DESC

Avato Chat Case: Finding influential users in the social network

// First create graph projection
CALL gds.graph.project(
  'avatoSocialGraph',
  ['User'],
  {
    FOLLOWS: {orientation: 'NATURAL'},
    FRIEND_OF: {orientation: 'UNDIRECTED'},
    MEMBER_OF_SAME_GROUP: {orientation: 'UNDIRECTED'}
  }
)

// Use PageRank algorithm to calculate user influence
CALL gds.pageRank.stream('avatoSocialGraph')
YIELD nodeId, score
MATCH (u:User) WHERE id(u) = nodeId
WITH u, score
// Get user activity metrics
MATCH (u)-[:SENT]->(m:Message)
WHERE m.sentTime > datetime() - duration('P30D')
WITH u, score, count(m) AS recentMessages
// Calculate comprehensive influence score
RETURN u.username, 
       score AS networkScore, 
       recentMessages,
       (score * 0.7 + (recentMessages/100) * 0.3) AS influenceScore
ORDER BY influenceScore DESC
LIMIT 20

This query uses graph algorithms to find the most influential users in the Avato Chat social network, providing data support for content recommendations and KOL marketing through comprehensive scoring based on network structure analysis and activity metrics.

2.6 Practical Case Analysis

2.6.1 Social Network Case

Avato Chat Social Network Case: Finding mutual friends:

MATCH (user1:User {username: 'alex_zhang'})-[:FRIEND|:COLLEAGUE]-(mutual:User)-[:FRIEND|:COLLEAGUE]-(user2:User {username: 'linda_wang'})
RETURN mutual.username AS MutualFriend, 
       collect(DISTINCT type((user1)-[]-(mutual))) AS user1Relations,
       collect(DISTINCT type((mutual)-[]-(user2))) AS user2Relations

Recommending potential friends:

MATCH (user:User {username: 'alex_zhang'})-[:FRIEND|:FOLLOWS|:MEMBER_OF]-(connection)
      -[:FRIEND|:FOLLOWS|:MEMBER_OF]-(potentialFriend:User)
WHERE NOT (user)-[:FRIEND|:FOLLOWS|:MEMBER_OF]-(potentialFriend) 
  AND user <> potentialFriend
  AND potentialFriend.privacySetting <> 'Private'
WITH potentialFriend, count(DISTINCT connection) AS connectionStrength,
     collect(DISTINCT connection.username) AS sharedConnections
MATCH (potentialFriend)-[:INTERESTED_IN]->(t:Topic)<-[:INTERESTED_IN]-(user)
WITH potentialFriend, connectionStrength, sharedConnections,
     count(t) AS sharedInterests
RETURN potentialFriend.username AS RecommendedFriend, 
       connectionStrength AS ConnectionStrength,
       sharedConnections[0..3] AS SampleSharedConnections,
       sharedInterests AS SharedInterests,
       connectionStrength * 0.7 + sharedInterests * 0.3 AS MatchScore
ORDER BY MatchScore DESC
LIMIT 10

Calculating social influence score:

MATCH (u:User)
WHERE u.activeStatus = 'Active'
// Content publication score
OPTIONAL MATCH (u)-[:POSTED]->(p:Post)
WHERE p.createdAt > datetime() - duration('P90D')
WITH u, count(DISTINCT p) AS postCount
// Interaction score
OPTIONAL MATCH (u)-[:SENT]->(m:Message) 
WHERE m.sentAt > datetime() - duration('P30D')
WITH u, postCount, count(m) AS messageCount
// Social connection score
OPTIONAL MATCH (u)-[:FRIEND|:FOLLOWS]->(connection)
WITH u, postCount, messageCount, count(connection) AS connectionCount
// Group activity score
OPTIONAL MATCH (u)-[:MEMBER_OF]->(g:Group)
WITH u, postCount, messageCount, connectionCount, count(g) AS groupCount
// Comprehensive influence score calculation
RETURN u.username, 
       u.registerDate,
       postCount * 10 AS ContentScore,
       messageCount * 0.5 AS EngagementScore,
       connectionCount * 2 AS NetworkScore,
       groupCount * 5 AS CommunityScore,
       postCount * 10 + messageCount * 0.5 + 
       connectionCount * 2 + groupCount * 5 AS TotalInfluenceScore
ORDER BY TotalInfluenceScore DESC
LIMIT 50

2.6.2 RGB Case

RGB Protocol Asset Case: Asset recommendations:

MATCH (w:Wallet {address: '1A2B3C'})-[:HOLDS]->(a:Asset)<-[:HOLDS]-(similar:Wallet)
MATCH (similar)-[:HOLDS]->(recommendation:Asset)
WHERE NOT (w)-[:HOLDS]->(recommendation)
  AND recommendation.protocol IN ['RGB-20', 'RGB-21', 'RGB-25']
  AND recommendation.status = 'Active'
WITH recommendation, count(DISTINCT similar) AS holders,
     recommendation.marketCap / count(DISTINCT similar) AS marketCapPerHolder
RETURN recommendation.name, 
       recommendation.symbol,
       recommendation.protocol AS AssetType,
       holders AS SimilarWalletsHolding,
       marketCapPerHolder AS MarketAdoption,
       recommendation.price,
       recommendation.priceChange24h
ORDER BY holders DESC, marketCapPerHolder DESC
LIMIT 15

Tracking asset transfer paths:

MATCH path = (asset:Asset {id: 'RGB20-USDT'})-[:TRANSFERRED*1..5]->(w:Wallet)
WHERE asset.createdAt > datetime() - duration('P30D')
RETURN [node IN nodes(path) | 
        CASE WHEN node:Asset THEN node.symbol 
             WHEN node:Wallet THEN node.address[0..8] + '...' 
             ELSE toString(node) 
        END] AS TransferPath,
       [rel IN relationships(path) | rel.timestamp] AS TransferTimes,

2.6.3 AvatoLabs Specific Cases

Avato Chat Social Relationship Analysis:

// Find the most active communities
MATCH (u:User)-[:MEMBER_OF]->(g:Group)
WITH g, count(u) AS members
MATCH (g)<-[:POSTED_IN]-(m:Message)
WITH g, members, count(m) AS messageCount
RETURN g.name AS Community, 
       members, 
       messageCount, 
       messageCount * 1.0 / members AS ActivityIndex
ORDER BY ActivityIndex DESC

RGB Protocol Asset Tracking:

// Track asset transfer paths
MATCH path = (asset:Asset {id: 'A1001'})-[:TRANSFERRED*1..10]->(:Wallet)
RETURN [node IN nodes(path) | 
        CASE 
          WHEN node:Asset THEN node.id
          WHEN node
0
Subscribe to my newsletter

Read articles from Marlon Shelby directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marlon Shelby
Marlon Shelby