from-Klauselnjoin-Klauselnlimit und offseteq(left, right)gt(left, right), gte(left, right), lt(left, right), lte(left, right)inArray(value, array)like(value, pattern), ilike(value, pattern)and(...conditions)or(...conditions)not(condition)upper(value), lower(value)length(value)concat(...values)add(left, right)coalesce(...values)count(value)sum(value)avg(value)min(value), max(value)TanStack DB bietet ein leistungsfähiges, typsicheres Abfragesystem, mit dem Sie Daten aus Sammlungen mithilfe einer SQL-ähnlichen, flüssigen API abrufen, filtern, transformieren und aggregieren können. Alle Abfragen sind standardmäßig **live**, d. h. sie aktualisieren sich automatisch, wenn sich die zugrunde liegenden Daten ändern.
Das Abfragesystem basiert auf einer API, die SQL-Abfrage-Buildern wie Kysely oder Drizzle ähnelt, bei der Sie Methoden aneinanderreihen, um Ihre Abfrage zu komponieren. Der Abfrage-Builder führt Operationen nicht in der Reihenfolge der Methodenaufrufe aus – stattdessen komponiert er Ihre Abfrage zu einer optimalen inkrementellen Pipeline, die effizient kompiliert und ausgeführt wird. Jede Methode gibt einen neuen Abfrage-Builder zurück, sodass Sie Operationen miteinander verketten können.
Live-Abfragen werden zu Sammlungen aufgelöst, die sich automatisch aktualisieren, wenn sich ihre zugrunde liegenden Daten ändern. Sie können Änderungen abonnieren, Ergebnisse durchlaufen und alle Standardmethoden für Sammlungen verwenden.
import { createCollection, liveQueryCollectionOptions, eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
email: user.email,
}))
}))
import { createCollection, liveQueryCollectionOptions, eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
email: user.email,
}))
}))
Die Ergebnistypen werden automatisch aus Ihrer Abfragestruktur abgeleitet und bieten vollständige TypeScript-Unterstützung. Wenn Sie eine select-Klausel verwenden, entspricht der Ergebnistyp Ihrer Projektion. Ohne select erhalten Sie das vollständige Schema mit korrekter Join-Optionalität.
Um eine Live-Query-Sammlung zu erstellen, können Sie liveQueryCollectionOptions mit createCollection verwenden oder die Komfortfunktion createLiveQueryCollection verwenden.
Die grundlegende Methode zum Erstellen einer Live-Abfrage ist die Verwendung von liveQueryCollectionOptions mit createCollection
import { createCollection, liveQueryCollectionOptions, eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
}))
import { createCollection, liveQueryCollectionOptions, eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
}))
Für mehr Kontrolle können Sie zusätzliche Optionen angeben
const activeUsers = createCollection(liveQueryCollectionOptions({
id: 'active-users', // Optional: auto-generated if not provided
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
})),
getKey: (user) => user.id, // Optional: uses stream key if not provided
startSync: true, // Optional: starts sync immediately
}))
const activeUsers = createCollection(liveQueryCollectionOptions({
id: 'active-users', // Optional: auto-generated if not provided
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
})),
getKey: (user) => user.id, // Optional: uses stream key if not provided
startSync: true, // Optional: starts sync immediately
}))
| Option | Typ | Beschreibung |
|---|---|---|
| id | string (optional) | Eine optionale eindeutige Kennung für die Live-Abfrage. Wenn nicht angegeben, wird sie automatisch generiert. Dies ist nützlich für Debugging und Protokollierung. |
| query | QueryBuilder oder Funktion | Die Abfragedefinition, dies ist entweder eine Query-Instanz oder eine Funktion, die eine Query-Instanz zurückgibt. |
| getKey | (item) => string | number (optional) | Eine Funktion, die einen eindeutigen Schlüssel aus jeder Zeile extrahiert. Wenn nicht angegeben, wird der interne Schlüssel des Streams verwendet. In einfachen Fällen ist dies der Schlüssel aus der übergeordneten Sammlung, aber im Falle von Joins ist der automatisch generierte Schlüssel eine Kombination der übergeordneten Schlüssel. Die Verwendung von getKey ist nützlich, wenn Sie einen bestimmten Schlüssel aus einer übergeordneten Sammlung für die resultierende Sammlung verwenden möchten. |
| schema | Schema (optional) | Optionales Schema für die Validierung |
| startSync | boolean (optional) | Ob die Synchronisierung sofort gestartet werden soll. Standardmäßig true. |
| gcTime | number (optional) | Garbage-Collection-Zeit in Millisekunden. Standardmäßig 5000 (5 Sekunden). |
Für einfachere Fälle können Sie createLiveQueryCollection als Abkürzung verwenden
import { createLiveQueryCollection, eq } from '@tanstack/db'
const activeUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
import { createLiveQueryCollection, eq } from '@tanstack/db'
const activeUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
In React können Sie den Hook useLiveQuery verwenden
import { useLiveQuery } from '@tanstack/react-db'
function UserList() {
const activeUsers = useLiveQuery((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
)
return (
<ul>
{activeUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
import { useLiveQuery } from '@tanstack/react-db'
function UserList() {
const activeUsers = useLiveQuery((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
)
return (
<ul>
{activeUsers.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)
}
Weitere Details zur Framework-Integration finden Sie in der Dokumentation der React- und Vue-Adapter.
Die Grundlage jeder Abfrage ist die Methode from, die die Quellsammlung oder Subquery angibt. Sie können die Quelle mithilfe von Objektsyntax aliasieren.
from({
[alias]: Collection | Query,
}): Query
from({
[alias]: Collection | Query,
}): Query
Parameter
Beginnen Sie mit einer grundlegenden Abfrage, die alle Datensätze aus einer Sammlung auswählt
const allUsers = createCollection(liveQueryCollectionOptions({
query: (q) => q.from({ user: usersCollection })
}))
const allUsers = createCollection(liveQueryCollectionOptions({
query: (q) => q.from({ user: usersCollection })
}))
Das Ergebnis enthält alle Benutzer mit ihrem vollständigen Schema. Sie können die Ergebnisse durchlaufen oder per Schlüssel darauf zugreifen
// Get all users as an array
const users = allUsers.toArray
// Get a specific user by ID
const user = allUsers.get(1)
// Check if a user exists
const hasUser = allUsers.has(1)
// Get all users as an array
const users = allUsers.toArray
// Get a specific user by ID
const user = allUsers.get(1)
// Check if a user exists
const hasUser = allUsers.has(1)
Verwenden Sie Aliase, um Ihre Abfragen lesbarer zu machen, insbesondere bei der Arbeit mit mehreren Sammlungen
const users = createCollection(liveQueryCollectionOptions({
query: (q) => q.from({ u: usersCollection })
}))
// Access fields using the alias
const userNames = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ u: usersCollection })
.select(({ u }) => ({
name: u.name,
email: u.email,
}))
}))
const users = createCollection(liveQueryCollectionOptions({
query: (q) => q.from({ u: usersCollection })
}))
// Access fields using the alias
const userNames = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ u: usersCollection })
.select(({ u }) => ({
name: u.name,
email: u.email,
}))
}))
Verwenden Sie where-Klauseln, um Ihre Daten basierend auf Bedingungen zu filtern. Sie können mehrere where-Aufrufe verketten – sie werden mit and-Logik kombiniert.
Die Methode where nimmt eine Callback-Funktion entgegen, die ein Objekt mit Ihren Tabellenaliassen erhält und einen booleschen Ausdruck zurückgibt. Sie erstellen diese Ausdrücke mit Vergleichsfunktionen wie eq(), gt() und logischen Operatoren wie and() und or(). Dieser deklarative Ansatz ermöglicht es dem Abfragesystem, Ihre Filter effizient zu optimieren. Diese werden im Abschnitt Referenz der Expressionsfunktionen detaillierter beschrieben. Dies ähnelt sehr der Art und Weise, wie Sie Abfragen mit Kysely oder Drizzle erstellen.
Es ist wichtig zu beachten, dass die Methode where keine Funktion ist, die für jede Zeile oder die Ergebnisse ausgeführt wird, sondern eine Möglichkeit, die auszuführende Abfrage zu beschreiben. Dieser deklarative Ansatz funktioniert für fast alle Anwendungsfälle gut, aber wenn Sie eine komplexere Bedingung verwenden müssen, gibt es die funktionale Variante als fn.where, die im Abschnitt Funktionale Varianten beschrieben wird.
where(
condition: (row: TRow) => Expression<boolean>
): Query
where(
condition: (row: TRow) => Expression<boolean>
): Query
Parameter
Benutzer nach einer einfachen Bedingung filtern
import { eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
}))
import { eq } from '@tanstack/db'
const activeUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
}))
Mehrere where-Aufrufe für AND-Logik verketten
import { eq, gt } from '@tanstack/db'
const adultActiveUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.where(({ user }) => gt(user.age, 18))
}))
import { eq, gt } from '@tanstack/db'
const adultActiveUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
.where(({ user }) => gt(user.age, 18))
}))
Logische Operatoren verwenden, um komplexe Bedingungen zu erstellen
import { eq, gt, or, and } from '@tanstack/db'
const specialUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) =>
and(
eq(user.active, true),
or(
gt(user.age, 25),
eq(user.role, 'admin')
)
)
)
)
import { eq, gt, or, and } from '@tanstack/db'
const specialUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) =>
and(
eq(user.active, true),
or(
gt(user.age, 25),
eq(user.role, 'admin')
)
)
)
)
Das Abfragesystem bietet mehrere Vergleichsoperatoren
import { eq, gt, gte, lt, lte, like, ilike, inArray, and, or, not } from '@tanstack/db'
// Equality
eq(user.id, 1)
// Comparisons
gt(user.age, 18) // greater than
gte(user.age, 18) // greater than or equal
lt(user.age, 65) // less than
lte(user.age, 65) // less than or equal
// String matching
like(user.name, 'John%') // case-sensitive pattern matching
ilike(user.name, 'john%') // case-insensitive pattern matching
// Array membership
inArray(user.id, [1, 2, 3])
// Logical operators
and(condition1, condition2)
or(condition1, condition2)
not(condition)
import { eq, gt, gte, lt, lte, like, ilike, inArray, and, or, not } from '@tanstack/db'
// Equality
eq(user.id, 1)
// Comparisons
gt(user.age, 18) // greater than
gte(user.age, 18) // greater than or equal
lt(user.age, 65) // less than
lte(user.age, 65) // less than or equal
// String matching
like(user.name, 'John%') // case-sensitive pattern matching
ilike(user.name, 'john%') // case-insensitive pattern matching
// Array membership
inArray(user.id, [1, 2, 3])
// Logical operators
and(condition1, condition2)
or(condition1, condition2)
not(condition)
Eine vollständige Referenz aller verfügbaren Funktionen finden Sie im Abschnitt Referenz der Expressionsfunktionen.
Verwenden Sie select, um anzugeben, welche Felder in Ihren Ergebnissen enthalten sein sollen, und um Ihre Daten zu transformieren. Ohne select erhalten Sie das vollständige Schema.
Ähnlich wie die where-Klausel nimmt die select-Methode eine Callback-Funktion entgegen, die ein Objekt mit Ihren Tabellenaliassen erhält und ein Objekt mit den Feldern zurückgibt, die Sie in Ihren Ergebnissen einschließen möchten. Diese können mit Funktionen aus dem Abschnitt Referenz der Expressionsfunktionen kombiniert werden, um berechnete Felder zu erstellen. Sie können auch den Spread-Operator verwenden, um alle Felder aus einer Tabelle einzuschließen.
select(
projection: (row: TRow) => Record<string, Expression>
): Query
select(
projection: (row: TRow) => Record<string, Expression>
): Query
Parameter
Bestimmte Felder aus Ihren Daten auswählen
const userNames = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
id: user.id,
name: user.name,
email: user.email,
}))
)
/*
Result type: { id: number, name: string, email: string }
```ts
for (const row of userNames) {
console.log(row.name)
}
```
*/
const userNames = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
id: user.id,
name: user.name,
email: user.email,
}))
)
/*
Result type: { id: number, name: string, email: string }
```ts
for (const row of userNames) {
console.log(row.name)
}
```
*/
Felder in Ihren Ergebnissen umbenennen
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
userId: user.id,
fullName: user.name,
contactEmail: user.email,
}))
)
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
userId: user.id,
fullName: user.name,
contactEmail: user.email,
}))
)
Berechnete Felder mit Ausdrücken erstellen
import { gt, length } from '@tanstack/db'
const userStats = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
id: user.id,
name: user.name,
isAdult: gt(user.age, 18),
nameLength: length(user.name),
}))
)
import { gt, length } from '@tanstack/db'
const userStats = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
id: user.id,
name: user.name,
isAdult: gt(user.age, 18),
nameLength: length(user.name),
}))
)
Ihre Daten mit integrierten Funktionen transformieren
import { concat, upper, gt } from '@tanstack/db'
const formattedUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
...user, // Include all user fields
displayName: upper(concat(user.firstName, ' ', user.lastName)),
isAdult: gt(user.age, 18),
}))
}))
/*
Result type:
{
id: number,
name: string,
email: string,
displayName: string,
isAdult: boolean,
}
*/
import { concat, upper, gt } from '@tanstack/db'
const formattedUsers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
...user, // Include all user fields
displayName: upper(concat(user.firstName, ' ', user.lastName)),
isAdult: gt(user.age, 18),
}))
}))
/*
Result type:
{
id: number,
name: string,
email: string,
displayName: string,
isAdult: boolean,
}
*/
Eine vollständige Liste der verfügbaren Funktionen finden Sie im Abschnitt Referenz der Expressionsfunktionen.
Verwenden Sie join, um Daten aus mehreren Sammlungen zu kombinieren. Joins sind standardmäßig vom Typ left und unterstützen nur Gleichheitsbedingungen.
Joins in TanStack DB sind eine Methode, um Daten aus mehreren Sammlungen zu kombinieren, und sind konzeptionell SQL-Joins sehr ähnlich. Wenn zwei Sammlungen verbunden werden, ist das Ergebnis eine neue Sammlung, die die kombinierten Daten als einzelne Zeilen enthält. Die neue Sammlung ist eine Live-Query-Sammlung und wird automatisch aktualisiert, wenn sich die zugrunde liegenden Daten ändern.
Ein join ohne select gibt Zeilenobjekte zurück, die mit den Aliassen der verbundenen Sammlungen benannt sind.
Der Ergebnistyp eines Joins berücksichtigt den Join-Typ, wobei die Optionalität der verbundenen Felder durch den Join-Typ bestimmt wird.
Hinweis
Wir arbeiten an einem include-System, das Joins ermöglicht, die zu einem hierarchischen Objekt projizieren. Zum Beispiel könnte eine issue-Zeile eine comments-Eigenschaft haben, die ein Array von comment-Zeilen ist. Siehe dieses Issue für weitere Details.
join(
{ [alias]: Collection | Query },
condition: (row: TRow) => Expression<boolean>, // Must be an `eq` condition
joinType?: 'left' | 'right' | 'inner' | 'full'
): Query
join(
{ [alias]: Collection | Query },
condition: (row: TRow) => Expression<boolean>, // Must be an `eq` condition
joinType?: 'left' | 'right' | 'inner' | 'full'
): Query
Parameter
Benutzer mit ihren Beiträgen verbinden
const userPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
)
/*
Result type:
{
user: User,
post?: Post, // post is optional because it is a left join
}
```ts
for (const row of userPosts) {
console.log(row.user.name, row.post?.title)
}
```
*/
const userPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
)
/*
Result type:
{
user: User,
post?: Post, // post is optional because it is a left join
}
```ts
for (const row of userPosts) {
console.log(row.user.name, row.post?.title)
}
```
*/
Geben Sie den Join-Typ als drittes Argument an
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
'inner', // `inner`, `left`, `right` or `full`
)
)
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
'inner', // `inner`, `left`, `right` or `full`
)
)
Oder verwenden Sie die Alias-Methoden leftJoin, rightJoin, innerJoin und fullJoin
// Left join - all users, even without posts
const allUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.leftJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user: User,
post?: Post, // post is optional because it is a left join
}
*/
// Left join - all users, even without posts
const allUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.leftJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user: User,
post?: Post, // post is optional because it is a left join
}
*/
// Right join - all posts, even without users
const allPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.rightJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user?: User, // user is optional because it is a right join
post: Post,
}
*/
// Right join - all posts, even without users
const allPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.rightJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user?: User, // user is optional because it is a right join
post: Post,
}
*/
// Inner join - only matching records
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.innerJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user: User,
post: Post,
}
*/
// Inner join - only matching records
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.innerJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user: User,
post: Post,
}
*/
// Full join - all users and all posts
const allUsersAndPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fullJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user?: User, // user is optional because it is a full join
post?: Post, // post is optional because it is a full join
}
*/
// Full join - all users and all posts
const allUsersAndPosts = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fullJoin(
{ post: postsCollection },
({ user, post }) => eq(user.id, post.userId),
)
)
/*
Result type:
{
user?: User, // user is optional because it is a full join
post?: Post, // post is optional because it is a full join
}
*/
Mehrere Joins in einer einzigen Abfrage verketten
const userPostComments = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
.join({ comment: commentsCollection }, ({ post, comment }) =>
eq(post.id, comment.postId)
)
.select(({ user, post, comment }) => ({
userName: user.name,
postTitle: post.title,
commentText: comment.text,
}))
)
const userPostComments = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
.join({ comment: commentsCollection }, ({ post, comment }) =>
eq(post.id, comment.postId)
)
.select(({ user, post, comment }) => ({
userName: user.name,
postTitle: post.title,
commentText: comment.text,
}))
)
Subqueries ermöglichen es Ihnen, das Ergebnis einer Abfrage als Eingabe für eine andere zu verwenden. Sie werden in die Abfrage selbst eingebettet und zu einer einzigen Abfragepipeline kompiliert. Sie sind SQL-Subqueries sehr ähnlich, die als Teil einer einzigen Operation ausgeführt werden.
Beachten Sie, dass Subqueries nicht dasselbe sind wie die Verwendung eines Live-Query-Ergebnisses in einer from- oder join-Klausel in einer neuen Abfrage. Wenn Sie dies tun, wird das Zwischenergebnis vollständig berechnet und Ihnen zugänglich gemacht, Subqueries sind intern für ihre übergeordnete Abfrage und nicht selbst zu einer Sammlung materialisiert, und sind daher effizienter.
Weitere Details zur Verwendung von Live-Query-Ergebnissen in einer from- oder join-Klausel in einer neuen Abfrage finden Sie im Abschnitt Zwischenergebnisse cachen.
Eine Subquery als Hauptquelle verwenden
const activeUserPosts = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery first
const activeUsers = q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use the subquery in the main query
return q
.from({ activeUser: activeUsers })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
}
}))
const activeUserPosts = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery first
const activeUsers = q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use the subquery in the main query
return q
.from({ activeUser: activeUsers })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
}
}))
Mit einem Subquery-Ergebnis verbinden
const userRecentPosts = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery first
const recentPosts = q
.from({ post: postsCollection })
.where(({ post }) => gt(post.createdAt, '2024-01-01'))
.orderBy(({ post }) => post.createdAt, 'desc')
.limit(1)
// Use the subquery in the main query
return q
.from({ user: usersCollection })
.join({ recentPost: recentPosts }, ({ user, recentPost }) =>
eq(user.id, recentPost.userId)
)
}
}))
const userRecentPosts = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery first
const recentPosts = q
.from({ post: postsCollection })
.where(({ post }) => gt(post.createdAt, '2024-01-01'))
.orderBy(({ post }) => post.createdAt, 'desc')
.limit(1)
// Use the subquery in the main query
return q
.from({ user: usersCollection })
.join({ recentPost: recentPosts }, ({ user, recentPost }) =>
eq(user.id, recentPost.userId)
)
}
}))
Wenn dieselbe Subquery mehrmals innerhalb einer Abfrage verwendet wird, wird sie automatisch dedupliziert und nur einmal ausgeführt
const complexQuery = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery once
const activeUsers = q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use the same subquery multiple times
return q
.from({ activeUser: activeUsers })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
.join({ comment: commentsCollection }, ({ activeUser, comment }) =>
eq(activeUser.id, comment.userId)
)
}
}))
const complexQuery = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the subquery once
const activeUsers = q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use the same subquery multiple times
return q
.from({ activeUser: activeUsers })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
.join({ comment: commentsCollection }, ({ activeUser, comment }) =>
eq(activeUser.id, comment.userId)
)
}
}))
In diesem Beispiel wird die Subquery activeUsers zweimal verwendet, aber nur einmal ausgeführt, was die Leistung verbessert.
Komplexe Abfragen mit mehreren Verschachtelungsebenen erstellen
import { count } from '@tanstack/db'
const topUsers = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the post count subquery
const postCounts = q
.from({ post: postsCollection })
.groupBy(({ post }) => post.userId)
.select(({ post }) => ({
userId: post.userId,
count: count(post.id),
}))
// Build the user stats subquery
const userStats = q
.from({ user: usersCollection })
.join({ postCount: postCounts }, ({ user, postCount }) =>
eq(user.id, postCount.userId)
)
.select(({ user, postCount }) => ({
id: user.id,
name: user.name,
postCount: postCount.count,
}))
.orderBy(({ userStats }) => userStats.postCount, 'desc')
.limit(10)
// Use the user stats subquery in the main query
return q.from({ userStats })
}
}))
import { count } from '@tanstack/db'
const topUsers = createCollection(liveQueryCollectionOptions({
query: (q) => {
// Build the post count subquery
const postCounts = q
.from({ post: postsCollection })
.groupBy(({ post }) => post.userId)
.select(({ post }) => ({
userId: post.userId,
count: count(post.id),
}))
// Build the user stats subquery
const userStats = q
.from({ user: usersCollection })
.join({ postCount: postCounts }, ({ user, postCount }) =>
eq(user.id, postCount.userId)
)
.select(({ user, postCount }) => ({
id: user.id,
name: user.name,
postCount: postCount.count,
}))
.orderBy(({ userStats }) => userStats.postCount, 'desc')
.limit(10)
// Use the user stats subquery in the main query
return q.from({ userStats })
}
}))
Verwenden Sie groupBy, um Ihre Daten zu gruppieren und Aggregatfunktionen anzuwenden. Wenn Sie Aggregate in select ohne groupBy verwenden, wird der gesamte Ergebnissatz als eine einzige Gruppe behandelt.
groupBy(
grouper: (row: TRow) => Expression | Expression[]
): Query
groupBy(
grouper: (row: TRow) => Expression | Expression[]
): Query
Parameter
Benutzer nach ihrer Abteilung gruppieren und zählen
import { count, avg } from '@tanstack/db'
const departmentStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => user.departmentId)
.select(({ user }) => ({
departmentId: user.departmentId,
userCount: count(user.id),
avgAge: avg(user.age),
}))
}))
import { count, avg } from '@tanstack/db'
const departmentStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => user.departmentId)
.select(({ user }) => ({
departmentId: user.departmentId,
userCount: count(user.id),
avgAge: avg(user.age),
}))
}))
Hinweis
In groupBy-Abfragen müssen die Eigenschaften in Ihrer select-Klausel entweder
Sie können keine Eigenschaften auswählen, die weder aggregiert noch gruppiert sind.
Nach mehreren Spalten gruppieren, indem ein Array aus dem Callback zurückgegeben wird
const userStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => [user.departmentId, user.role])
.select(({ user }) => ({
departmentId: user.departmentId,
role: user.role,
count: count(user.id),
avgSalary: avg(user.salary),
}))
}))
const userStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => [user.departmentId, user.role])
.select(({ user }) => ({
departmentId: user.departmentId,
role: user.role,
count: count(user.id),
avgSalary: avg(user.salary),
}))
}))
Verschiedene Aggregatfunktionen verwenden, um Ihre Daten zusammenzufassen
import { count, sum, avg, min, max } from '@tanstack/db'
const orderStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalOrders: count(order.id),
totalAmount: sum(order.amount),
avgOrderValue: avg(order.amount),
minOrder: min(order.amount),
maxOrder: max(order.amount),
}))
}))
import { count, sum, avg, min, max } from '@tanstack/db'
const orderStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalOrders: count(order.id),
totalAmount: sum(order.amount),
avgOrderValue: avg(order.amount),
minOrder: min(order.amount),
maxOrder: max(order.amount),
}))
}))
Eine vollständige Liste der verfügbaren Aggregatfunktionen finden Sie im Abschnitt Aggregatfunktionen.
Aggregierte Ergebnisse mit having filtern – dies ähnelt der where-Klausel, wird aber nach Abschluss der Aggregation angewendet.
having(
condition: (row: TRow) => Expression<boolean>
): Query
having(
condition: (row: TRow) => Expression<boolean>
): Query
Parameter
const highValueCustomers = createLiveQueryCollection((q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalSpent: sum(order.amount),
orderCount: count(order.id),
}))
.having(({ order }) => gt(sum(order.amount), 1000))
)
const highValueCustomers = createLiveQueryCollection((q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalSpent: sum(order.amount),
orderCount: count(order.id),
}))
.having(({ order }) => gt(sum(order.amount), 1000))
)
Wenn Sie Aggregate ohne groupBy verwenden, wird der gesamte Ergebnissatz gruppiert
const overallStats = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
totalUsers: count(user.id),
avgAge: avg(user.age),
maxSalary: max(user.salary),
}))
)
const overallStats = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.select(({ user }) => ({
totalUsers: count(user.id),
avgAge: avg(user.age),
maxSalary: max(user.salary),
}))
)
Dies entspricht der Gruppierung der gesamten Sammlung in eine einzige Gruppe.
Gruppierte Ergebnisse können über den Gruppenschlüssel abgerufen werden
const deptStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => user.departmentId)
.select(({ user }) => ({
departmentId: user.departmentId,
count: count(user.id),
}))
}))
// Access by department ID
const engineeringStats = deptStats.get(1)
const deptStats = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.groupBy(({ user }) => user.departmentId)
.select(({ user }) => ({
departmentId: user.departmentId,
count: count(user.id),
}))
}))
// Access by department ID
const engineeringStats = deptStats.get(1)
Hinweis: Gruppierte Ergebnisse werden basierend auf der Gruppierung unterschiedlich geschlüsselt
- Gruppierung nach einer Spalte: Geschlüsselt nach dem tatsächlichen Wert (z. B. deptStats.get(1))
- Gruppierung nach mehreren Spalten: Geschlüsselt nach einem JSON-String der gruppierten Werte (z. B. userStats.get('[1,"admin"]'))
Verwenden Sie orderBy, limit und offset, um die Reihenfolge und Paginierung Ihrer Ergebnisse zu steuern. Die Sortierung erfolgt inkrementell für optimale Leistung.
orderBy(
selector: (row: TRow) => Expression,
direction?: 'asc' | 'desc'
): Query
limit(count: number): Query
offset(count: number): Query
orderBy(
selector: (row: TRow) => Expression,
direction?: 'asc' | 'desc'
): Query
limit(count: number): Query
offset(count: number): Query
Parameter
Ergebnisse nach einer einzelnen Spalte sortieren
const sortedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.name)
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
const sortedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.name)
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
Nach mehreren Spalten sortieren
const sortedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.departmentId, 'asc')
.orderBy(({ user }) => user.name, 'asc')
.select(({ user }) => ({
id: user.id,
name: user.name,
departmentId: user.departmentId,
}))
)
const sortedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.departmentId, 'asc')
.orderBy(({ user }) => user.name, 'asc')
.select(({ user }) => ({
id: user.id,
name: user.name,
departmentId: user.departmentId,
}))
)
Verwenden Sie desc für absteigende Reihenfolge
const recentPosts = createLiveQueryCollection((q) =>
q
.from({ post: postsCollection })
.orderBy(({ post }) => post.createdAt, 'desc')
.select(({ post }) => ({
id: post.id,
title: post.title,
createdAt: post.createdAt,
}))
)
const recentPosts = createLiveQueryCollection((q) =>
q
.from({ post: postsCollection })
.orderBy(({ post }) => post.createdAt, 'desc')
.select(({ post }) => ({
id: post.id,
title: post.title,
createdAt: post.createdAt,
}))
)
Ergebnisse mit offset überspringen
const page2Users = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.name, 'asc')
.limit(20)
.offset(20) // Skip first 20 results
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
const page2Users = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.orderBy(({ user }) => user.name, 'asc')
.limit(20)
.offset(20) // Skip first 20 results
.select(({ user }) => ({
id: user.id,
name: user.name,
}))
)
Erstellen Sie komplexe Abfragen durch Zusammensetzung kleinerer, wiederverwendbarer Teile. Dieser Ansatz macht Ihre Abfragen wartbarer und ermöglicht durch Caching eine bessere Leistung.
Abfragen basierend auf Laufzeitbedingungen erstellen
import { Query, eq } from '@tanstack/db'
function buildUserQuery(options: { activeOnly?: boolean; limit?: number }) {
let query = new Query().from({ user: usersCollection })
if (options.activeOnly) {
query = query.where(({ user }) => eq(user.active, true))
}
if (options.limit) {
query = query.limit(options.limit)
}
return query.select(({ user }) => ({
id: user.id,
name: user.name,
}))
}
const activeUsers = createLiveQueryCollection(buildUserQuery({ activeOnly: true, limit: 10 }))
import { Query, eq } from '@tanstack/db'
function buildUserQuery(options: { activeOnly?: boolean; limit?: number }) {
let query = new Query().from({ user: usersCollection })
if (options.activeOnly) {
query = query.where(({ user }) => eq(user.active, true))
}
if (options.limit) {
query = query.limit(options.limit)
}
return query.select(({ user }) => ({
id: user.id,
name: user.name,
}))
}
const activeUsers = createLiveQueryCollection(buildUserQuery({ activeOnly: true, limit: 10 }))
Das Ergebnis einer Live-Query-Sammlung ist selbst eine Sammlung und wird automatisch aktualisiert, wenn sich die zugrunde liegenden Daten ändern. Das bedeutet, dass Sie das Ergebnis einer Live-Query-Sammlung als Quelle in einer anderen Live-Query-Sammlung verwenden können. Dieses Muster ist nützlich für die Erstellung komplexer Abfragen, bei denen Sie Zwischenergebnisse cachen möchten, um weitere Abfragen zu beschleunigen.
// Base query for active users
const activeUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
)
// Query that depends on active users
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: activeUsers })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
.select(({ user, post }) => ({
userName: user.name,
postTitle: post.title,
}))
)
// Base query for active users
const activeUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
)
// Query that depends on active users
const activeUserPosts = createLiveQueryCollection((q) =>
q
.from({ user: activeUsers })
.join({ post: postsCollection }, ({ user, post }) =>
eq(user.id, post.userId)
)
.select(({ user, post }) => ({
userName: user.name,
postTitle: post.title,
}))
)
Sie können die Query-Klasse verwenden, um wiederverwendbare Abfragedefinitionen zu erstellen. Dies ist nützlich für die Erstellung komplexer Abfragen, bei denen Sie dieselbe Abfrage-Builder-Instanz mehrmals in Ihrer Anwendung wiederverwenden möchten.
import { Query, eq } from '@tanstack/db'
// Create a reusable query builder
const userQuery = new Query()
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use it in different contexts
const activeUsers = createLiveQueryCollection({
query: userQuery.select(({ user }) => ({
id: user.id,
name: user.name,
}))
})
// Or as a subquery
const userPosts = createLiveQueryCollection((q) =>
q
.from({ activeUser: userQuery })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
)
import { Query, eq } from '@tanstack/db'
// Create a reusable query builder
const userQuery = new Query()
.from({ user: usersCollection })
.where(({ user }) => eq(user.active, true))
// Use it in different contexts
const activeUsers = createLiveQueryCollection({
query: userQuery.select(({ user }) => ({
id: user.id,
name: user.name,
}))
})
// Or as a subquery
const userPosts = createLiveQueryCollection((q) =>
q
.from({ activeUser: userQuery })
.join({ post: postsCollection }, ({ activeUser, post }) =>
eq(activeUser.id, post.userId)
)
)
Verwenden Sie Ref<MyType>, um wiederverwendbare Callback-Funktionen zu erstellen
import { Ref, eq, gt, and } from '@tanstack/db'
// Create reusable callbacks
const isActiveUser = (user: Ref<User>) => eq(user.active, true)
const isAdultUser = (user: Ref<User>) => gt(user.age, 18)
// Use them in queries
const activeAdults = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => and(isActiveUser(user), isAdultUser(user)))
.select(({ user }) => ({
id: user.id,
name: user.name,
age: user.age,
}))
}))
import { Ref, eq, gt, and } from '@tanstack/db'
// Create reusable callbacks
const isActiveUser = (user: Ref<User>) => eq(user.active, true)
const isAdultUser = (user: Ref<User>) => gt(user.age, 18)
// Use them in queries
const activeAdults = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.where(({ user }) => and(isActiveUser(user), isAdultUser(user)))
.select(({ user }) => ({
id: user.id,
name: user.name,
age: user.age,
}))
}))
Sie können auch Callbacks erstellen, die die gesamte Zeile empfangen und sie direkt an where übergeben
// Callback that takes the whole row
const isHighValueCustomer = (row: { user: User; order: Order }) =>
row.user.active && row.order.amount > 1000
// Use directly in where clause
const highValueCustomers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.join({ order: ordersCollection }, ({ user, order }) =>
eq(user.id, order.userId)
)
.where(isHighValueCustomer)
.select(({ user, order }) => ({
userName: user.name,
orderAmount: order.amount,
}))
}))
// Callback that takes the whole row
const isHighValueCustomer = (row: { user: User; order: Order }) =>
row.user.active && row.order.amount > 1000
// Use directly in where clause
const highValueCustomers = createCollection(liveQueryCollectionOptions({
query: (q) =>
q
.from({ user: usersCollection })
.join({ order: ordersCollection }, ({ user, order }) =>
eq(user.id, order.userId)
)
.where(isHighValueCustomer)
.select(({ user, order }) => ({
userName: user.name,
orderAmount: order.amount,
}))
}))
Dieser Ansatz macht Ihre Abfragelogik modularer und testbarer.
Das Abfragesystem bietet eine umfassende Reihe von Funktionen zum Filtern, Transformieren und Aggregieren von Daten.
Gleichheitsvergleich
eq(user.id, 1)
eq(user.name, 'John')
eq(user.id, 1)
eq(user.name, 'John')
Numerische, Zeichenketten- und Datumvergleiche
gt(user.age, 18)
gte(user.salary, 50000)
lt(user.createdAt, new Date('2024-01-01'))
lte(user.rating, 5)
gt(user.age, 18)
gte(user.salary, 50000)
lt(user.createdAt, new Date('2024-01-01'))
lte(user.rating, 5)
Überprüfen, ob ein Wert in einem Array vorhanden ist
inArray(user.id, [1, 2, 3])
inArray(user.role, ['admin', 'moderator'])
inArray(user.id, [1, 2, 3])
inArray(user.role, ['admin', 'moderator'])
Zeichenkettenmusterabgleich
like(user.name, 'John%') // Case-sensitive
ilike(user.email, '%@gmail.com') // Case-insensitive
like(user.name, 'John%') // Case-sensitive
ilike(user.email, '%@gmail.com') // Case-insensitive
Bedingungen mit AND-Logik kombinieren
and(
eq(user.active, true),
gt(user.age, 18),
eq(user.role, 'user')
)
and(
eq(user.active, true),
gt(user.age, 18),
eq(user.role, 'user')
)
Bedingungen mit OR-Logik kombinieren
or(
eq(user.role, 'admin'),
eq(user.role, 'moderator')
)
or(
eq(user.role, 'admin'),
eq(user.role, 'moderator')
)
Eine Bedingung negieren
not(eq(user.active, false))
not(eq(user.active, false))
Groß-/Kleinschreibung umwandeln
upper(user.name) // 'JOHN'
lower(user.email) // 'john@example.com'
upper(user.name) // 'JOHN'
lower(user.email) // 'john@example.com'
Länge von Zeichenketten oder Arrays abrufen
length(user.name) // String length
length(user.tags) // Array length
length(user.name) // String length
length(user.tags) // Array length
Zeichenketten verketten
concat(user.firstName, ' ', user.lastName)
concat('User: ', user.name, ' (', user.id, ')')
concat(user.firstName, ' ', user.lastName)
concat('User: ', user.name, ' (', user.id, ')')
Zwei Zahlen addieren
add(user.salary, user.bonus)
add(user.salary, user.bonus)
Den ersten Nicht-NULL-Wert zurückgeben
coalesce(user.displayName, user.name, 'Unknown')
coalesce(user.displayName, user.name, 'Unknown')
Nicht-NULL-Werte zählen
count(user.id) // Count all users
count(user.postId) // Count users with posts
count(user.id) // Count all users
count(user.postId) // Count users with posts
Numerische Werte summieren
sum(order.amount)
sum(user.salary)
sum(order.amount)
sum(user.salary)
Durchschnitt berechnen
avg(user.salary)
avg(order.amount)
avg(user.salary)
avg(order.amount)
Minimal- und Maximalwerte finden
min(user.salary)
max(order.amount)
min(user.salary)
max(order.amount)
Funktionen können komponiert und verkettet werden
// Complex condition
and(
eq(user.active, true),
or(
gt(user.age, 25),
eq(user.role, 'admin')
),
not(inArray(user.id, bannedUserIds))
)
// Complex transformation
concat(
upper(user.firstName),
' ',
upper(user.lastName),
' (',
user.id,
')'
)
// Complex aggregation
avg(add(user.salary, coalesce(user.bonus, 0)))
// Complex condition
and(
eq(user.active, true),
or(
gt(user.age, 25),
eq(user.role, 'admin')
),
not(inArray(user.id, bannedUserIds))
)
// Complex transformation
concat(
upper(user.firstName),
' ',
upper(user.lastName),
' (',
user.id,
')'
)
// Complex aggregation
avg(add(user.salary, coalesce(user.bonus, 0)))
Die funktionale Variantenschnittstelle bietet eine Alternative zur Standard-API und bietet mehr Flexibilität für komplexe Transformationen. Bei funktionalen Varianten enthalten die Callback-Funktionen tatsächlichen Code, der ausgeführt wird, um die Operation durchzuführen, und geben Ihnen die volle Leistung von JavaScript zur Verfügung.
Warnung
Die funktionale Variantenschnittstelle kann vom Abfrageoptimierer nicht optimiert werden und keine Sammlungsindizes verwenden. Sie ist für seltene Fälle gedacht, in denen die Standard-API nicht ausreicht.
Verwenden Sie fn.select() für komplexe Transformationen mit JavaScript-Logik
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row) => ({
id: row.user.id,
displayName: `${row.user.firstName} ${row.user.lastName}`,
salaryTier: row.user.salary > 100000 ? 'senior' : 'junior',
emailDomain: row.user.email.split('@')[1],
isHighEarner: row.user.salary > 75000,
}))
)
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row) => ({
id: row.user.id,
displayName: `${row.user.firstName} ${row.user.lastName}`,
salaryTier: row.user.salary > 100000 ? 'senior' : 'junior',
emailDomain: row.user.email.split('@')[1],
isHighEarner: row.user.salary > 75000,
}))
)
Verwenden Sie fn.where() für komplexe Filterlogik
const specialUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.where((row) => {
const user = row.user
return user.active &&
(user.age > 25 || user.role === 'admin') &&
user.email.includes('@company.com')
})
)
const specialUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.where((row) => {
const user = row.user
return user.active &&
(user.age > 25 || user.role === 'admin') &&
user.email.includes('@company.com')
})
)
Verwenden Sie fn.having() für komplexe Aggregationsfilterung
const highValueCustomers = createLiveQueryCollection((q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalSpent: sum(order.amount),
orderCount: count(order.id),
}))
.fn.having((row) => {
return row.totalSpent > 1000 && row.orderCount >= 3
})
)
const highValueCustomers = createLiveQueryCollection((q) =>
q
.from({ order: ordersCollection })
.groupBy(({ order }) => order.customerId)
.select(({ order }) => ({
customerId: order.customerId,
totalSpent: sum(order.amount),
orderCount: count(order.id),
}))
.fn.having((row) => {
return row.totalSpent > 1000 && row.orderCount >= 3
})
)
Funktionale Varianten eignen sich hervorragend für komplexe Datentransformationen
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row) => {
const user = row.user
const fullName = `${user.firstName} ${user.lastName}`.trim()
const emailDomain = user.email.split('@')[1]
const ageGroup = user.age < 25 ? 'young' : user.age < 50 ? 'adult' : 'senior'
return {
userId: user.id,
displayName: fullName || user.name,
contactInfo: {
email: user.email,
domain: emailDomain,
isCompanyEmail: emailDomain === 'company.com'
},
demographics: {
age: user.age,
ageGroup: ageGroup,
isAdult: user.age >= 18
},
status: user.active ? 'active' : 'inactive',
profileStrength: fullName && user.email && user.age ? 'complete' : 'incomplete'
}
})
)
const userProfiles = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row) => {
const user = row.user
const fullName = `${user.firstName} ${user.lastName}`.trim()
const emailDomain = user.email.split('@')[1]
const ageGroup = user.age < 25 ? 'young' : user.age < 50 ? 'adult' : 'senior'
return {
userId: user.id,
displayName: fullName || user.name,
contactInfo: {
email: user.email,
domain: emailDomain,
isCompanyEmail: emailDomain === 'company.com'
},
demographics: {
age: user.age,
ageGroup: ageGroup,
isAdult: user.age >= 18
},
status: user.active ? 'active' : 'inactive',
profileStrength: fullName && user.email && user.age ? 'complete' : 'incomplete'
}
})
)
Funktionale Varianten behalten die vollständige TypeScript-Unterstützung
const processedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row): ProcessedUser => ({
id: row.user.id,
name: row.user.name.toUpperCase(),
age: row.user.age,
ageGroup: row.user.age < 25 ? 'young' : row.user.age < 50 ? 'adult' : 'senior',
}))
)
const processedUsers = createLiveQueryCollection((q) =>
q
.from({ user: usersCollection })
.fn.select((row): ProcessedUser => ({
id: row.user.id,
name: row.user.name.toUpperCase(),
age: row.user.age,
ageGroup: row.user.age < 25 ? 'young' : row.user.age < 50 ? 'adult' : 'senior',
}))
)
Verwenden Sie funktionale Varianten, wenn Sie benötigen
Die Callbacks in funktionalen Varianten sind tatsächliche JavaScript-Funktionen, die ausgeführt werden, im Gegensatz zur Standard-API, die deklarative Ausdrücke verwendet. Dies gibt Ihnen die volle Kontrolle über die Logik, bringt aber den Kompromiss reduzierter Optimierungsmöglichkeiten mit sich.
Ziehen Sie jedoch wann immer möglich die Standard-API vor, da diese eine bessere Leistung und Optimierungsmöglichkeiten bietet.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.