Relation Class Documentation
The Relation class provides a mechanism to handle relationships between collections in a database. It supports one-to-one, one-to-many, and many-to-many relationships.
Class: Relation
Constructor: Relation(dbs)
Creates a new instance of the Relation class.
- Parameters:
dbs(RelationTypes.DBS): An object mapping database names toValtheraClassor compatible instances.
async findOne(path, search, relations, select?)
Finds a single entry in a collection and resolves its relations.
- Parameters:
path(RelationTypes.Path): A tuple[dbName, collectionName]specifying the database and collection.search(Search): The search criteria.relations(RelationTypes.Relation): The relations to resolve.-
select(string[][] | Record<string, any>, optional): Fields to include in the result. Accepts array of paths or an object with paths as values. -
Returns:
Promise<Object | null>: The found entry with resolved relations, ornullif no match is found.
async find(path, search, relations, select?, dbFindOpts?)
Finds multiple entries in a collection and resolves their relations.
- Parameters:
path(RelationTypes.Path): A tuple[dbName, collectionName]specifying the database and collection.search(Search): The search criteria.relations(RelationTypes.Relation): The relations to resolve.select(string[][] | Record<string, any>, optional): Fields to include in the results.-
dbFindOpts(DbFindOpts, optional): Options for the find operation (pagination, sorting, etc.). -
Returns:
Promise<Object[]>: An array of found entries with resolved relations.
Relation Types
The Relation class supports the following relation types:
"1" - One-to-One (Batch)
Resolves a single related entry per document using a batched $in query. This is the most performant one-to-one mode.
{
author: {
path: ["main", "users"],
pk: "_id", // field on the source document
fk: "_id", // field on the related document
type: "1"
}
}
"11" - One-to-One (Individual)
Similar to "1", but internally performs a findOne operation for each document during a find query. Less performant but useful with custom adapters or legacy systems.
{
author: {
path: ["main", "users"],
pk: "_id",
fk: "authorId",
type: "11"
}
}
"1n" - One-to-Many
Resolves multiple related entries. Supports dbFindOpts for sorting/pagination of related items.
{
posts: {
path: ["main", "posts"],
pk: "_id",
fk: "authorId",
type: "1n",
dbFindOpts: { limit: 10, sortBy: "createdAt", sortAsc: false }
}
}
"nm" - Many-to-Many
Resolves all entries via a pivot/join table. Requires the through option.
{
tags: {
path: ["main", "tags"],
pk: "_id",
fk: "_id",
type: "nm",
through: {
table: "post_tags", // pivot collection name
pk: "postId", // pivot field referencing source
fk: "tagId", // pivot field referencing target
db: "main" // optional: database name for pivot (defaults to source db)
}
}
}
Configuration Options
Each relation entry supports these options:
| Option | Type | Default | Description |
|---|---|---|---|
path |
[string, string] |
required | [dbName, collectionName] of the related data |
pk |
string |
"_id" |
Field on the source document to match |
fk |
string |
"_id" |
Field on the related document to match |
type |
"1" \| "11" \| "1n" \| "nm" |
"1" |
Relationship type |
as |
string |
relation key name | Field name in the result object |
select |
string[] |
undefined |
Fields to include from related documents |
dbFindOpts |
DbFindOpts |
{} |
Options for "1n" type (sorting, pagination) |
through |
Object |
undefined |
Pivot table config for "nm" type |
relations |
Relation |
undefined |
Nested relations to resolve on related documents |
Nested Relations
Relations can be nested to resolve deeply linked data:
const relations = {
author: {
path: ["main", "users"],
pk: "_id",
fk: "_id",
type: "1",
relations: {
// Resolve relations on the author document itself
recentPosts: {
path: ["main", "posts"],
pk: "_id",
fk: "authorId",
type: "1n"
}
}
},
comments: {
path: ["main", "comments"],
pk: "_id",
fk: "postId",
type: "1n",
relations: {
// Resolve relations on each comment
author: {
path: ["main", "users"],
pk: "authorId",
fk: "_id",
type: "1"
}
}
}
};
The as Option
By default, the relation is stored under the key name used in the relations object. Use as to rename it:
const relations = {
writer: { // key name
path: ["main", "users"],
pk: "authorId",
fk: "_id",
type: "1",
as: "author" // stored as result.author, not result.writer
}
};
The select Option
Use select to limit which fields are included from related documents. The foreign key field is automatically added and removed to avoid duplication:
{
author: {
path: ["main", "users"],
pk: "_id",
fk: "_id",
type: "1",
select: ["name", "email"] // only these fields are returned
}
}
select accepts an array of field paths. You can also pass an object to findOne/find as the select parameter for result-level field selection:
const post = await relation.findOne(
["main", "posts"],
{ _id: "post123" },
relations,
{ title: true, author: { name: true } } // object form
);
Example Usage
import { Relation } from "@wxn0brp/db-core";
import { ValtheraCreate } from "@wxn0brp/db";
// Create database instances
const db1 = ValtheraCreate("./db1");
const db2 = ValtheraCreate("./db2");
// Define databases
const dbs = {
db1,
db2
};
// Define relations
const relations = {
author: {
path: ["db1", "users"],
pk: "authorId",
fk: "_id",
type: "1",
select: ["name", "email"]
},
comments: {
path: ["db2", "comments"],
pk: "_id",
fk: "postId",
type: "1n",
dbFindOpts: { limit: 20, sortBy: "createdAt", sortAsc: false }
}
};
// Create a Relation instance
const relation = new Relation(dbs);
// Find a single post with relations
const post = await relation.findOne(
["db1", "posts"],
{ _id: "post123" },
relations,
[["title"], ["author.name"], ["comments.content"]]
);
console.log(post);
// Find multiple posts with relations
const posts = await relation.find(
["db1", "posts"],
{ category: "tech" },
relations,
[["title"], ["author.name"], ["comments.content"]],
{ limit: 10 }
);
console.log(posts);