Skip to content

live query docs #242

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 20, 2025
Merged

live query docs #242

merged 10 commits into from
Jul 20, 2025

Conversation

samwillis
Copy link
Collaborator

@samwillis samwillis commented Jul 8, 2025

Copy link

changeset-bot bot commented Jul 8, 2025

⚠️ No Changeset found

Latest commit: 0b23f0b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link

pkg-pr-new bot commented Jul 8, 2025

@tanstack/db-example-react-todo

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@242

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@242

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@242

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@242

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@242

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@242

commit: 0b23f0b

Copy link
Contributor

github-actions bot commented Jul 8, 2025

Size Change: 0 B

Total Size: 38.6 kB

ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection.js 8.68 kB
./packages/db/dist/esm/deferred.js 230 B
./packages/db/dist/esm/errors.js 150 B
./packages/db/dist/esm/index.js 568 B
./packages/db/dist/esm/local-only.js 827 B
./packages/db/dist/esm/local-storage.js 2.09 kB
./packages/db/dist/esm/optimistic-action.js 294 B
./packages/db/dist/esm/proxy.js 4.19 kB
./packages/db/dist/esm/query/builder/functions.js 531 B
./packages/db/dist/esm/query/builder/index.js 3.68 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 842 B
./packages/db/dist/esm/query/compiler/evaluators.js 1.34 kB
./packages/db/dist/esm/query/compiler/group-by.js 2.09 kB
./packages/db/dist/esm/query/compiler/index.js 1.75 kB
./packages/db/dist/esm/query/compiler/joins.js 1.2 kB
./packages/db/dist/esm/query/compiler/order-by.js 933 B
./packages/db/dist/esm/query/compiler/select.js 657 B
./packages/db/dist/esm/query/ir.js 318 B
./packages/db/dist/esm/query/live-query-collection.js 2.07 kB
./packages/db/dist/esm/query/optimizer.js 2.24 kB
./packages/db/dist/esm/SortedMap.js 1.24 kB
./packages/db/dist/esm/transactions.js 2.29 kB
./packages/db/dist/esm/utils.js 419 B

compressed-size-action::db-package-size

Copy link
Contributor

github-actions bot commented Jul 8, 2025

Size Change: 0 B

Total Size: 1.05 kB

ℹ️ View Unchanged
Filename Size
./packages/react-db/dist/esm/index.js 152 B
./packages/react-db/dist/esm/useLiveQuery.js 902 B

compressed-size-action::react-db-package-size

Copy link
Collaborator

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it!


### Convenience Function

For simpler cases, you can use `createLiveQueryCollection` as a shortcut:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want this? We explicitly went down the two function calls as a way of being explicit about how collections work & I'd rather keep things consistent — people can certainly add their own convenience functions if they'd like

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking here is that this could be the exception to the rule. Users will be very regularly be creating liveQueryCollections outside of components, in loaders and other places, and if we don't provide this wrapper they will after a while get frustrated and make it themselves. The intention is that it exposes the same api as the useLiveQuery, you just use the callback to build your query, so moving between the two doesn't require any different structures in your code.

This is a strong opinion (I would expect it from the lib), but but weakly held - if you felt equally strongly that we should remove it then let's do that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I don't feel that strongly against it 👍 so let's keep it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@KyleAMathews on this, we are likely to want a createLiveQueryCollections (plural) that can return multiple multiple collection from a single query pipeline. Thats where the liveQueryCollectionOptions falls down, it imposes a 1:1 query-to-collection relationship. We certainly keep it, but it's worth considering what this looks like when we move on to that.

@samwillis samwillis marked this pull request as ready for review July 19, 2025 09:53
@samwillis samwillis changed the title DRAFT live query docs live query docs Jul 19, 2025
Copy link
Collaborator

@KyleAMathews KyleAMathews left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: great stuff!

Copy link
Contributor

@thruflo thruflo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff. Fantastic reference, lots of information, very clear and well organised.

```ts
import { createCollection, liveQueryCollectionOptions, eq } from '@tanstack/db'

const activeUsers = createCollection(liveQueryCollectionOptions({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was surprised to see the use of createCollection(liveQueryCollectionOptions({ in most of the code examples.

So far, most of my use of live queries has been in a component context with useLiveQuery. Below later on you switch to the more convenient createLiveQueryCollection. And then also introduce the Query class.

Using createCollection(liveQueryCollectionOptions({ is a lot of "collection" for creating a query.


### Using liveQueryCollectionOptions

The fundamental way to create a live query is using `liveQueryCollectionOptions` with `createCollection`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the existing PR discussion below. To share my viewpoint (which is perhaps slightly fresh / less deep in the weeds):

  1. if we have createLiveQueryCollection then that is simpler for examples (that don't need the extra flexibility) than the createCollection(liveQueryCollectionOptions({
  2. the most common starting points to use live queries is in component context, with useLiveQuery

I think this section Creating Live Query Collections all really emphasises that live queries are collections. I'm not sure this is necessary. It's like "yes a live query is a collection but it's also a live query". Like the page is called "live queries". Could this section be "Creating Live Queries" and start with a "live queries can be created and used in a few different ways. The most common is in a component using useLiveQuery but they can also be created standalone using createLiveQuery and composable using the lower level Query builder".

Note my dropping of the Collection suffix from createLiveQuery. Then still explain that a live query is a collection and show that the longer createCollection(liveQueryCollectionOptions( is equivalent with more flexibility. But then the examples can more clearly generally use createLiveQuery?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another perspective on this is that if live queries are just collections then perhaps we should be talking about querying collections, not about live queries. I.e.: either a live query is a thing and a collection is a thing. Or they are one thing and collections are just queryable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, having leand into the concept that a "live query is a collection", I fear we are going to break that distinction more as we expand the live query capabilities.

We currently have this 1:1 relationship of live query to collection but thats not going to be the case soon.

This is a common pattern that I think we will want to support:

const { totalCount, pagedResults } = useLiveQuery((q) => {
  const baseQuery = q
    .from({ issues: issueCollection })
    .where(({ issue }) => eq(issue.projectId, 123))
    .where(/* more complex expressions from UI filters */)
  
  const totalCount = baseQuery
    .select(({ issue} ) => ({
      count: count(issue.id)
    }))
  
  const pagedResults = baseQuery
    .orderBy(({ issue }) => issue.data)
    .limit(30)
    
  return { totalCount, pagedResults }
})

// Render the total results count in a header, and then the paged results below.
// (note the I have some ideas now to reuse the same query for paging through 
// results, but thats another thing later on)

With that I feel we need to more away from the 1:1 relationship.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't totalCount and pagedResults both be collections? We're not breaking the connection if useLiveQuery gets more complex.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, they are still collections. However rather than a live query collection being constructed by using liveQueryCollectionOptions and passing that to a collection, we have to have a factory that takes a query and returns 1+ collections.

It's no longer Collection passed Options, which are in turn passed a Query, it's a Query processed to output multiple Collections.

There are lots of nuances that will need solving, such as the lifecycle of the Collection no longer being 1:1 with its query as that query may be being used by multiple collections.


Live queries are just collections that automatically update when their underlying data changes. You can subscribe to changes, iterate over results, and use all the standard collection methods.

## Table of Contents
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think another section or aspect that's maybe not currently covered in this guide is query dependencies.

When queries are defined/derived from other queries/collections then they automatically update when their source queries/collections change.

When queries are defined using JS variables then their definitions do not change. In a component context, this is addressed with useLiveQuery where you pass a dependencies array.

The mechanism for handling dependency changes in the latter case is much more blunt than in the former.

I think it's worth outlining how this stuff works. Perhaps the meat of the usage with dependencies belongs to the specific framework docs. However I think the principle should be established here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure where best to place info on the deps array, but suspect in the React docs. Vue for example should not need the deps array and its not part of the apis discussed here. I do agree is complex and maybe needs highlighting more.

@samwillis samwillis requested a review from thruflo July 20, 2025 17:10
@samwillis
Copy link
Collaborator Author

I'm merging this now as there is useful information, we can continue to iterate in further PRs

@samwillis samwillis merged commit d08c46d into main Jul 20, 2025
4 of 5 checks passed
@samwillis samwillis deleted the samwillis/query-docs branch July 20, 2025 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants