The power of programming, in your database
TypeDB enables software engineers to build data applications faster, with a modern language that avoids complexity.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
match
$user isa user,
has full-name $name,
has email $email;
fetch
$name;
$email;
# This returns all users of any type
match
$user isa employee,
has full-name $name,
has email $email,
has employee-id $id;
fetch
$name;
$email;
$id;
# This returns only users who are employees
match
$user-type sub user;
$user isa $user-type,
has full-name $name,
has email $email;
fetch
$name;
$email;
$user-type;
# This returns all users and their type
Every data point has a type that you define, like employee
. Types can also be subtypes of other types, like user
. So, a query for user
entities could return both employee
and contractor
entities, without the query having to specify this. We call this polymorphism, and it drastically simplifies how you interact with your database.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
insert
$john isa full-time-employee,
has full-name "John Doe",
has primary-email "john.doe@typedb.com",
has email "j.doe@typedb.com",
has email "john@typedb.com",
has employee-id 183;
$readme isa file, has path "/home/johndoe/repos/typedb/readme.md";
$edit isa action, has name "edit file";
$kevin isa user, has email "kevin@typedb.com";
$perm (subject: $john, object: $readme, action: $edit) isa permission;
$rqst (target: $perm, requestee: $kevin) isa change-request, has requested-change "revoke";
Types, attributes and relations aren’t things you have to implement: they’re core features. With the freedom to model hierarchies, multi-valued attributes, n-ary relations, nested relations and more, the conceptual data model is the data model. This makes database design, and writing queries, incredibly intuitive.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
define
user sub entity,
owns full-name,
owns email @unique;
employee sub user,
owns employee-id @key,
plays team-membership:member;
membership sub relation, abstract,
relates parent,
relates member;
team-membership sub membership,
relates team as parent;
full-name sub attribute, value string;
id sub attribute, value string;
email sub id;
employee-id sub id;
TypeDB ensures conceptual consistency between your type hierarchies and declared type behaviours. This allows the schema to be trivially extended with no migrations or downtime. You can create abstract types and override supertype properties within the schema, bringing the expressive power of OOP to the database layer.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
match
$user isa user;
fetch
$user: full-name;
match
$user isa user, has email "john@typedb.com";
fetch
$user: full-name;
match
$user isa user, has email "john@typedb.com";
(subject: $user, object: $tql, action: $action) isa permission;
$tql isa file, has extension "tql";
fetch
$user: full-name;
match
$user isa user;
(subject: $user, object: $tql, action: $action) isa permission;
$tql isa file, has extension "tql";
(team: $eng, member: $user) isa team-membership;
$eng isa team, has name "Engineering";
fetch
$user: full-name;
TypeQL works through declarative pattern matching, allowing queries to be scoped to any level in the type hierarchy without considering physical data stores or execution strategy. As a composable language, concatenating two valid patterns will always produce a new valid one. Thanks to the high level of abstraction and near-natural syntax, domain experts can instantly understand a query's intent even with no knowledge of TypeQL.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
define
weekly-hours sub attribute value long;
full-time-employee sub employee;
part-time-employee sub employee, owns weekly-hours;
insert
$francois isa full-time-employee,
has full-name "François Durand",
has email "francois@typedb.com",
has employee-id 184,
has weekly-hours 35;
# [THW03] Invalid Write: Attribute of type 'weekly-hours' is
# not defined to be owned by type 'full-time-employee'.
With declarative schemas backed by static type checking, all queries are validated to ensure nonsensical writes are automatically blocked, and nonsensical reads throw an exception instead of returning an empty result set. Sessions and transactions are also strongly typed, preventing unauthorized and unintentional modifications from committing.
Model data directly as entities with attributes and relations
Designing your database requires nothing more than describing the real things your data represents. This puts an end to ‘object-relational mismatch’. You no longer need to think about your data in a different way between your application and your database.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
insert
$john isa full-time-employee,
has full-name "John Doe",
has primary-email "john.doe@typedb.com",
has email "j.doe@typedb.com",
has email "john@typedb.com",
has employee-id 183;
$readme isa file, has path "/home/johndoe/repos/typedb/readme.md";
$edit isa action, has name "edit file";
$kevin isa user, has email "kevin@typedb.com";
$perm (subject: $john, object: $readme, action: $edit) isa permission;
$rqst (target: $perm, requestee: $kevin) isa change-request, has requested-change "revoke";
TypeDB uses the Enhanced Entity-Relationship model with a declarative schema and static type checking. This allows the natural implementation of a type hierarchy, multivalued attributes, and n-ary and nested relations. Leverage OOP concepts like abstraction, inheritance, and polymorphism without warping the conceptual model. Normalization, null values, and reification are things of the past.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
DO $$
DECLARE
inserted_user_id INTEGER;
inserted_resource_id INTEGER;
inserted_action_id INTEGER;
inserted_requestee_id INTEGER;
inserted_permission_id INTEGER;
BEGIN
INSERT INTO users (id, full_name)
VALUES (DEFAULT, 'John Doe')
RETURNING id INTO inserted_user_id;
INSERT INTO user_emails (user_id, email, is_primary)
VALUES
(inserted_user_id, 'john.doe@typedb.com', TRUE),
(inserted_user_id, 'j.doe@typedb.com', FALSE),
(inserted_user_id, 'john@typedb.com', FALSE);
INSERT INTO employees (user_id, employee_id)
VALUES (inserted_user_id, 183);
INSERT INTO full_time_employees (user_id)
VALUES (inserted_user_id);
INSERT INTO resources (id)
VALUES (DEFAULT)
RETURNING id INTO inserted_resource_id;
INSERT INTO files (inserted_resource_id, path)
VALUES (inserted_resource_id, '/home/johndoe/repos/typedb/readme.md');
INSERT INTO actions (id, name)
VALUES (DEFAULT, 'edit file')
RETURNING id INTO inserted_action_id;
INSERT INTO users (id, full_name)
VALUES (DEFAULT, NULL)
RETURNING id INTO inserted_requestee_id;
INSERT INTO user_emails (user_id, email, is_primary)
VALUES (inserted_requestee_id, 'kevin@typedb.com', FALSE);
INSERT INTO permissions (id, subject, object, action)
VALUES (DEFAULT, inserted_user_id, inserted_resource_id, inserted_action_id)
RETURNING id INTO inserted_permission_id;
INSERT INTO change_requests (id, target, requestee, requested_change)
VALUES (DEFAULT, inserted_permission_id, inserted_requestee_id, 'revoke');
COMMIT;
END $$;
SQL was designed in a pre-OOP era. Schemas and queries quickly grow out of control when implementing class-table inheritance and normalizing multivalued attributes. Inheritance is also impossible to implement without losing referential integrity. This can only be fixed with brittle constraint-defining syntax that requires continual maintenance or integrity control in the application layer.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
db.change_requests.aggregate([
{
$lookup: {
from: "permissions",
localField: "target",
foreignField: "_id",
as: "permission"
}
},
{
$unwind: {
path: "$permission"
}
},
{
$lookup: {
from: "users",
localField: "user",
foreignField: "_id",
as: "user"
}
},
{
$unwind: {
path: "$user"
}
},
{
$lookup: {
from: "users",
localField: "permission.user",
foreignField: "_id",
as: "permission.user"
}
},
{
$unwind: {
path: "$permission.user"
}
},
{
$lookup: {
from: "identifiers",
localField: "permission.object",
foreignField: "_id",
as: "permission.object"
}
},
{
$unwind: {
path: "$permission.object"
}
},
{
$lookup: {
from: "actions",
localField: "permission.action",
foreignField: "_id",
as: "permission.action"
}
},
{
$unwind: {
path: "$permission.action"
}
},
{
$project: {
_id: false,
user: "$permission.user.email",
requestee: "$user.email",
target: "$permission.object.identifier",
action: "$permission.action.name",
request: "$req_change"
}
}
])
Document databases are designed and optimized to store hierarchical data. They can easily store multivalued attributes as list fields and null values as the absence of fields. However, inserting and retrieving highly interconnected data is complicated and poorly optimized. All similarly shaped data is dumped into the same collection without a schema, leaving the backend developer responsible for maintaining integrity and structure.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
MATCH
(john:User),
(readme:File {path: "/home/johndoe/repos/typedb/readme.md"}),
(edit:Action {name: "edit file"})
WHERE (
john.primary_email = "john@typedb.com"
OR "john@typedb.com" IN john.alias_emails
) AND NOT EXISTS {
MATCH (john)<-[:SUBJECT]-(perm:Permission)-[:OBJECT]->(readme)
WHERE EXISTS ( (perm)-[:ACTION]->(edit) )
}
WITH john, readme, edit
CREATE (john)<-[:SUBJECT]-(perm:Permission)-[:OBJECT]->(readme)
WITH edit, perm
CREATE (perm)-[:ACTION]->(edit);
MATCH
(perm:Permission),
(perm)-[:SUBJECT]->(john:User),
(perm)-[:OBJECT]->(readme:File {id: "/home/typedb/repos/typedb/readme.md"}),
(perm)-[:ACTION]->(edit:Action {name: "edit file"}),
(kevin:User)
WHERE (
john.primary_email = "john@typedb.com"
OR "john@typedb.com" IN john.alias_emails
) AND (
kevin.primary_email = "kevin@typedb.com"
OR "kevin@typedb.com" IN kevin.alias_emails
)
CREATE
(rqst:ChangeRequest {requested_change: "revoke"}),
(rqst)-[:TARGET]->(perm),
(rsqt)-[:REQUESTEE]->(kevin);
Graph databases, despite excelling at storing traditional graph-like data, cannot natively express relations other than strictly binary ones between two entities. This forces you to reify the model: turn relationships from edges into nodes, blurring the lines between entity and relation. Polymorphism is challenging to handle without a proper schema, forcing type hierarchies to be implemented as structureless data labels.
Modify your data model without refactoring or migrating
Extending an SQL database often involves a lengthy migration process. With TypeDB, you can extend your model without refactoring your queries or application code. Everything still works, because the data logic is in the structure, not the query.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
match
$user isa user, has email $email;
$rsrc isa! $resource-type, has id $id;
$resource-type sub resource;
$own (resource: $rsrc, owner: $user) isa resource-ownership;
fetch
$email;
$resource-type;
$id;
TypeDB is a truly polymorphic database. Queries are written in a high-level declarative language and resolved against the schema at query-time. Variables implicitly match all valid types, so queries never have to be updated when new subtypes are added. Attributes and relations are always implemented in the same way, so cardinality changes never require a change to the underlying model. All this means that extensions to the data model are trivial, and don't require refactors.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
SELECT
ue.email AS email,
'file' AS resource_type,
f.path AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN files f
ON r.id = f.resource_id
UNION ALL
SELECT
ue.email AS email,
'directory' AS resource_type,
d.path AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN directories d
ON r.id = d.resource_id
UNION ALL
SELECT
ue.email AS email,
'commit' AS resource_type,
c.hash AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN commits c
ON r.id = c.resource_id
UNION ALL
SELECT
ue.email AS email,
'repository' AS resource_type,
re.name AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN repositories re
ON r.id = re.resource_id
UNION ALL
SELECT
ue.email AS email,
'table' AS resource_type,
t.name AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN tables t
ON r.id = t.resource_id
UNION ALL
SELECT
ue.email AS email,
'database' AS resource_type,
f.name AS id
FROM users u
JOIN user_emails ue
ON u.id = ue.user_id
JOIN resource_ownerships ro
ON u.id = ro.user_id
JOIN resources r
ON ro.resource_id = r.id
JOIN databases d
ON r.id = d.resource_id;
SQL's inability to natively model inheritance and polymorphism leads to brittle queries that must explicitly describe all data to be returned. When the data model changes, many queries cease to be valid, requiring extensive modifications to your application code. Not only does data need to be carefully migrated to maintain integrity, but the migration process extends outside of the database to any application components that need to interact with it.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
db.resource_ownerships.aggregate( [
{
$lookup:
{
from: "resources",
localField: "resource",
foreignField: "_id",
as: "resource"
}
},
{
$unwind:
{
path: "$resource"
}
},
{
$lookup:
{
from: "users",
localField: "owner",
foreignField: "_id",
as: "owner"
}
},
{
$unwind:
{
path: "$owner"
}
},
{
$unwind:
{
path: "$owner.emails"
}
},
{
$addFields:
{
resource_id: {
$switch: {
branches: [
{
case: {
$eq: ["$resource.resource_type", "file"]
},
then: "$resource.path"
},
{
case: {
$eq: ["$resource.resource_type", "directory"]
},
then: "$resource.path"
},
{
case: {
$eq: ["$resource.resource_type", "commit"]
},
then: "$resource.hash"
},
{
case: {
$eq: ["$resource.resource_type", "repository"]
},
then: "$resource.name"
},
{
case: {
$eq: ["$resource.resource_type", "table"]
},
then: "$resource.name"
},
{
case: {
$eq: ["$resource.resource_type", "database"]
},
then: "$resource.name"
}
]
}
}
}
},
{
$project: {
_id: false,
email: "$owner.emails",
resource_type: "$resource.resource_type",
id: "$resource_id"
}
}
] )
With document databases, the freeform structure makes inserting data trivial, but writing and validating queries a significant challenge. Migrating data relies on complete knowledge of its layout to ensure that no errors are introduced. When the layout of the data changes, any queries or code that rely on the previous structure stop working. The complex and brittle aggregation pipelines are particularly difficult to maintain and troubleshoot, especially when utilising lookups across multiple collections.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
MATCH
(user:User)-[:OWNS]->(rsrc:Resource)
WITH
rsrc,
[user.primary_email] + user.alias_emails AS emails,
labels(rsrc) AS resource_types,
keys(rsrc) AS properties
UNWIND emails AS email
UNWIND resource_types AS resource_type
WITH
rsrc, email, resource_type, properties,
{
File: "path",
Directory: "path",
Commit: "hash",
Repository: "name",
Table: "name",
Database: "name"
} AS id_type_map
WHERE resource_type IN keys(id_type_map)
AND id_type_map[resource_type] IN properties
RETURN email, resource_type, rsrc[id_type_map[resource_type]] AS id
In graph databases, properties are attached directly to the nodes that own them rather than being nodes themselves. Relocating attributes between nodes or reifying relations causes breaking changes to queries that rely on them. These changes to the logical data model and queries must be manually carried out due to the lack of a schema to define structure. Those model discrepancies can lead to data inconsistency and integrity issues.
Queries run in real-time on a single source of truth
TypeDB has the performance to resolve even complex queries in milliseconds. So you never need to precompute results or store redundant copies, which can result in stale, inconsistent and incorrect results. Work with a single source of truth, all the time.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
define
rule transitive-team-membership:
when {
(team: $team-1, member: $team-2) isa team-membership;
(team: $team-2, member: $member) isa team-membership;
} then {
(team: $team-1, member: $member) isa team-membership;
};
match
$user isa user, has email $email;
$team isa team, has name $name;
(team: $team, member: $user) isa team-membership;
fetch
$email;
$name;
TypeDB's built-in reasoning engine allows rules to be defined in the schema and resolved at query time. Rules are constructed using first-order logic and define how new facts can be inferred from existing data. When a query is issued, matching rules are triggered using the most recent data available. This allows all computed data to be built on a single source of truth, ensuring accuracy and consistency without delay or redundancy.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
CREATE PROCEDURE reload_inherited_team_memberships()
LANGUAGE SQL
BEGIN ATOMIC
TRUNCATE TABLE inherited_team_memberships;
WITH RECURSIVE parent_teams (team, member) AS (
SELECT team_memberships.team, team_memberships.member
FROM team_memberships
WHERE team_memberships.member IN (
SELECT id
FROM user
)
UNION ALL
SELECT team_memberships.team, team_memberships.member
FROM team_memberships
JOIN parent_teams
ON parent_teams.team = team_memberships.member
)
INSERT INTO inherited_team_memberships (team, member)
SELECT team, member
FROM parent_teams;
COMMIT;
END;
SELECT users.email AS email, teams.name AS name
FROM inherited_team_memberships
JOIN users
ON users.id = inherited_team_memberships.member
JOIN teams
ON teams.id = inherited_team_memberships.team;
SQL's stored procedures enable computed data to be generated periodically. As modern data has grown in complexity, they have ceased to be performant enough for real-time use. Stale data accumulates as updates aren't immediately reflected, creating inconsistencies between the source and derived data. Scripts calling multiple procedures can even leave the data in an incorrect state due to propagating errors or race conditions.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
inherited_team_memberships = db.team_memberships.aggregate([
{
$lookup: {
from: "users",
localField: "member",
foreignField: "_id",
as: "member"
}
},
{
$unwind: {
path: "$member"
}
},
{
$graphLookup: {
from: "team_memberships",
startWith: "$team",
connectFromField: "team",
connectToField: "member",
as: "parent_teams"
}
},
{
$project: {
_id: false,
email: "$member.email",
team: {
$setUnion: [
[
"$team"
],
"$parent_teams.team"
]
}
}
},
{
$unwind: {
path: "$team"
}
},
{
$lookup: {
from: "teams",
localField: "team",
foreignField: "_id",
as: "team"
}
},
{
$unwind: {
path: "$team"
}
},
{
$project: {
email: "$email",
name: "$team.name"
}
}
])
db.inherited_team_memerships.remove({})
db.inherited_team_memberships.insertMany(inherited_team_memberships)
db.inherited_team_memberships.find({})
Document databases struggle to query efficiently when foreign document references are used to connect multiple collections. Lookup functions in aggregation pipelines require developers to explicitly identify and traverse every possible path between documents, forming a long and brittle pipeline. Missing or dissimilar fields in input documents silently generate bad data, requiring the pipeline to be painstakingly debugged stage-by-stage.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
MATCH
()<-[sub:SUBJECT]-(perm:InheritedPermission)-[obj:OBJECT]->(),
(perm)-[act:ACTION]->()
DELETE sub, obj, act, perm;
MATCH
(perm:Permission),
(user:User),
(rsrc:Resource),
(actn:Action)
WHERE (
(perm)-[:SUBJECT]->(user:User)
OR (perm)-[:SUBJECT]->(:Team)<-[:MEMBER_OF*]-(user:User)
) AND (
(perm)-[:OBJECT]->(rsrc:Resource)
OR (perm)-[:OBJECT]->(:Collection)<-[:MEMBER_OF*]-(rsrc:Resource)
) AND (
(perm)-[:ACTION]->(actn:Action)
OR (perm)-[:ACTION]->(:ActionSet)<-[:MEMBER_OF*]-(actn:Action)
) AND NOT EXISTS {
MATCH (user)<-[:SUBJECT]-(perm:InheritedPermission)-[:OBJECT]->(rsrc)
WHERE EXISTS ( (perm)-[:ACTION]->(actn) )
}
WITH user, rsrc, actn
CREATE (user)<-[:SUBJECT]-(perm:InheritedPermission)-[:OBJECT]->(rsrc)
WITH actn, perm
CREATE (perm)-[:ACTION]->(actn);
MATCH
(user:User)<-[:SUBJECT]-(perm:InheritedPermission)-[:OBJECT]->(rsrc:Resource),
(perm)-[:ACTION]->(actn:Action)
RETURN user, rsrc, actn;
Neo4j excels at identifying simple transitive relationships, but branching patterns are harder to express. This forces developers to specify all potential combinations of nodes, relationships, and properties, resulting in unmaintainable queries and poor performance. Because Neo4j lacks the expressive power of symbolic reasoning, these queries must be periodically executed to precompute the results, leading to stale and inconsistent data.
Robust developer tools
We provide and maintain a whole ecosystem of reliable tools and documentation that make developing with TypeDB a joy.
Instant setup
Run in a local Docker container or on AWS, GCP, and Azure with TypeDB Cloud, no dependencies/config needed.
Learn more
Powerful tools
Manage databases, build and execute queries, and explore results with TypeDB Studio, a cross-platform IDE.
Learn more
Robust APIs
Build complex and high-volume transactional applications with reactive and resilient open-source clients.
Learn more
Full support for your favorite language
We provide and officially support native drivers for all the languages below. Our APIs are asynchronous, reactive, stateful, and programmatic.
Go
go get github.com/typedb/typedb-driver/go
Request your language
Get started in the cloud for free
TypeDB Cloud is a fully-managed cloud database for your application, starting at $0/month with generous limits. Once your application needs it, upgrade for enterprise-level availability, auto-scaling, security and access control.
Global deployment, cloud agnosticDeploy in regions across AWS, GCP, and Azure, with different databases in different cloud providers and regions. | |
Scalability on demand, native clusteringConnect to clusters with topology-aware clients which can load balance requests across multiple replicas within a cluster. | |
Secure by default, roles and encryptionEnsure a high level of protection to safeguard data and maintain confidentiality with fully secured by default, with authentication as well as storage and network encryption. | |
Always available, automatic failoverGuarantee constant access to data thanks to synchronous replication and replicas which will automatically failover if the primary fails. | |
Teams and projects, organizational governanceCreate teams, members and projects to manage databases across the entire organization with ease. |
Supported by a global community
The TypeDB community is vibrant, active and always helpful. Join us on Discord or make contributions on GitHub. New faces are always welcome.
Developers love TypeDB
With its simple yet immensely powerful query language, native support for N-ary relationships and focus on semantic schema, TypeDB solves all our modeling problems so that we can focus more on solving higher level problems instead of tweaking traditional graph databases to fit our use cases.
Ram Anvesh
TypeDB enables us to model the supply chains of large Global CPG clients and identify environmental and social risks. We have found its strongly typed nature and expressivity to be world leading, allowing our customers to gain novel insights. With TypeDB, we can solve problems at the world's greatest companies.
Dixit Shah
For developers, TypeDB is really easy to work with. Its unique and expressive type system enables us to spend less time data modeling. We can easily integrate complex biomedical datasets. TypeDB provides us the backbone to our therapeutics platform to cure neurodegenerative diseases.
Nik Sharma
TypeDB's expressivity allows us to unify all levels of cyber intelligence for cyber security knowledge management systems. Through nested and hyper relations, we can easily represent TTPs and observables, attribution and victimology. During an attack, this gives analysts 360 views of any observable.
Samuel Hassine
TypeDB is a powerful framework for data exploration. The way data, attributes and relations can be expressed in a polymorphic manner allows us to build a rich network of multi-levels analysis and open opportunities to query, discover and infer interactions.
Jean-Paul Mochet
TypeDB provides a strongly-typed database with N-ary relations that enables modeling the world much closer to reality compared to other databases. In addition, its built-in inference engine enables to build next generation AI systems — one of the many reasons to choose TypeDB to model biomedical data.
Konrad Myśliwiec
TypeDB makes it easy for our robots to operate autonomously in the real world by being the centre of their understanding. TypeDB makes it easy to incorporate expert knowledge and advanced reasoning into its knowledge base.
Joris Sijs
Get started
Start building
Cloud or container, a polymorphic database with a conceptual data model, a strong subtyping system, a symbolic reasoning engine, and a type-theoretic language is minutes away.