Database collections
Collections represent groups of documents with similar structures, like tables for SQL databases. They create structure in an otherwise chaotic world. Every document created in DefraDB belongs to a collection.
A collection has a name (ex. Book) and a number of typed fields (ex. title: String).
type Book {
title: String
plot: String
rating: Float
}
Field types
Fields can be of different types:
Int: A signed 32‐bit integer.Float: A signed double-precision floating-point value.String: A UTF‐8 character sequence.Boolean:trueorfalse.ID: A unique identifier. Although theIDtype is serialized in the same way as aString, defining it as an ID communicates that it is not intended to be human‐readable.DateTime: (ex.2017-07-23T03:46:56.647Z)JSON: A JSON string (ex.{ "privacy": {"is": "sexy"} }). JSON fields get specially indexed.Blob: A hex string (ex.00FF).- List: An array of another type (ex.
[String]). Lists can not be nested.
Create collections
You can create a collection with either the CLI command defradb client collection add, the HTTP API endpoint /collections, or the method AddCollection.
- CLI
- HTTP API
- Embedded
defradb client collection add '
type Book {
title: String
plot: String
rating: Float
}
'
POST http://localhost:9181/api/v1/collections
type Book {
title: String
plot: String
rating: Float
}
_, err = db.DB.AddCollection(ctx, `type Book {
title: String
plot: String
rating: Float
}`)
if err != nil {
// Fails for example if the collection is already added
log.Fatalf("Failed to add collection: %v", err)
}
Relationships
To create a relationship between two types, define a field having the other side of the relationship as type.
The way in which you define relationships depends on their kind:
- One-to-one – Each document of one type is linked to one and only one document of the other type.
- One-to-many – Each document of one type is linked to multiple documents of the other type.
- Many-to-many – Each document of one type is linked to multiple documents of the other type.
See also: Create documents with relationships and Query the database.
One-to-one
One-to-one relationships are such that each document of one type is linked to one and only one document of another type.
In practice, type A defines a field of type B, and type B defines a field of type A. For example, there's a one-to-one relationship between Husband and Wife (disregarding avant-garde polyamorous relationships).
type Husband {
name: String
wife: Wife
}
type Wife {
name: String
husband: Husband @primary @index(unique: true)
}
@primary– This side stores a direct pointer to the other end of the relationship, resulting in faster queries. In the example above,Wifecontains a (implicit) field_husbandID, so retrieving a wife's husband is quick. On the other hand, documents of typeHusbanddo not contain any pointer to the relativeWife, so a collection scan is needed to retrieve a husband's wife. Which side should be primary depends on your query patterns.index(unique: true)– Creates a unique index on_husbandID, making the relationship one-to-one.
There's currently no validation on the type when creating documents with relationships. It is the client's responsibility to validate that the Wife.husbandID is populated with the docID of a Husband document. It's up to you to marry humans.
One-to-many
One-to-many relationships link one document of one type with many documents of another type. Type A defines a field of type B, whereas type B defines a field of type [A] (list of A). For example, each book is written by one author, whereas one author can write multiple books.
type Book {
title: String
author: Author
}
type Author {
name: String
authoredBooks: [Book]
}
There's currently no validation on the type when creating documents with relationships. It is the client's responsibility to validate that the Book.authorID is populated with the docID of a Author document.
Many-to-many
Many-to-many relationships link multiple documents of one type to multiple documents of another type. In DefraDB, you achieve this with two one-to-many relationships and a join type. For example, a student can enroll in many courses, and a course can have many students enrolled.
type Student {
name: String
age: Int
enrollment: [Enrollment]
}
type Course {
title: String
code: String
enrollment: [Enrollment]
}
type Enrollment {
student: Student
course: Course
}
Rename a relationship field
By default,
type Husband {
name: String
wife: Wife
}
type Wife {
name: String
husband: Husband @primary @index(unique: true)
}
Show collections
To see all collections available on an instance, use the CLI command defradb client collection describe or the HTTP API endpoint /collections.
- CLI
- HTTP API
defradb client collection describe
Use the --name parameter to request a specific collection by its name.
GET http://localhost:9181/api/v1/collections
Use the name parameter to request a specific collection by its name.
[
{
"Name": "Book",
"VersionID": "bafyreihqndwux4ewnlvmtcfvptikfvzu76tri2i5x4nbpiqh3hskxmagcm",
"CollectionID": "bafyreihqndwux4ewnlvmtcfvptikfvzu76tri2i5x4nbpiqh3hskxmagcm",
"CollectionSet": null,
"Query": null,
"PreviousVersion": null,
"Fields": [
{
"FieldID": "bafyreihqzhiz3iwro4jozp6kphq4sosg6ccoqcbiaf7rg5dmvea7aux55a",
"Name": "_docID",
"Kind": 1,
"Typ": 0,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreiguuxtuepj5vji3oe5j6lyhwqi5izm4all3gav7ppvgj35hxklrte",
"Name": "_authorID",
"Kind": 1,
"Typ": 1,
"RelationName": "book_person",
"IsPrimary": true,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreibhohsw25uzzzbzs2awta43ql5oo6anry3rxdcuj2n3hlfbjmifse",
"Name": "author",
"Kind": {
"Array": false,
"CollectionID": "bafyreifilnntrughum4p63ntvocxvwqg2eveymltpziwk7lluvncjftula"
},
"Typ": 0,
"RelationName": "book_person",
"IsPrimary": true,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreibxx5wzp4iagt3jifid2r7hfzvbtzp2fuq26vku6t6ptk3ppwgxl4",
"Name": "plot",
"Kind": 11,
"Typ": 1,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreibbxpehr5radbbkkmsau5uuscoif4dxu6j3ef4by6f445fyx7pl3y",
"Name": "rating",
"Kind": 6,
"Typ": 1,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
},
{
"FieldID": "bafyreihfb2izf5akjuua5jkijrgsgievsspboopupjq2its25owgle5pzm",
"Name": "title",
"Kind": 11,
"Typ": 1,
"RelationName": null,
"IsPrimary": false,
"DefaultValue": null,
"Size": 0
}
],
"Indexes": [],
"EncryptedIndexes": [],
"Policy": null,
"IsActive": true,
"IsMaterialized": true,
"IsBranchable": false,
"IsEmbeddedOnly": false,
"IsPlaceholder": false,
"VectorEmbeddings": []
}
]
Delete collections
To delete a collection, you need to truncate it (i.e. delete all its documents) and patch it for deletion.
- CLI
- HTTP API
Use the CLI commands defradb client collection truncate and defradb client collection patch.
For example, to delete the collection Book:
defradb client collection truncate --collection-id bafyreihqndwux4ewnlvmtcfvptikfvzu76tri2i5x4nbpiqh3hskxmagcm
defradb client collection patch '[{"op": "remove", "path": "/Book"}]'
Send a DELETE request to the endpoint /collections/<name> and a PATCH request to the endpoint /collections/.
For example, to delete the collection Book:
DELETE http://localhost:9181/api/v1/collections/Book HTTP/2
content-type: application/json
{}
PATCH http://localhost:9181/api/v1/collections/ HTTP/2
content-type: application/json
{
"Patch": "[{\"op\": \"remove\", \"path\": \"/Book\"}]"
}