Skip to content

add a .findOne() to query build to return the first item #182

Closed

Description

@KyleAMathews

e.g. instead of:

const { data: users } = useLiveQuery(
  (q) =>
    q
      .from({ usersCollection })
      .where(`@usersCollection.id`, `=`, userId),
  [userId]
)
const user = users[0]

We could write:

const { data: user } = useLiveQuery(
  (q) =>
    q
      .from({ usersCollection })
      .where(`@usersCollection.id`, `=`, userId)
      .findOne(),
  [userId]
)

Activity

  1. samwillis commented on Jun 17, 2025

    @samwillis
    Collaborator

    The query is materialised into a collection, we would need to find a way to not have a collection to make this work. Maybe it's a feature of the hook rather than the query?

    We will also need a stable order, so it may require an orderBy.

    Alternatively we do a one off query first to get the first item, then just subscribe to that.

    Note that with a orderBy and a limit(1) you don't need users[0], but it's still a collection.

  2. KyleAMathews commented on Jun 17, 2025

    @KyleAMathews
    CollaboratorAuthor

    Oh limit(1) already turns it into an object instead of an array?

  3. KyleAMathews commented on Jun 17, 2025

    @KyleAMathews
    CollaboratorAuthor

    no it doesn't :-D

    Yeah, the hook could just see that findOne is on the query & return the first object.

  4. KyleAMathews commented on Jun 17, 2025

    @KyleAMathews
    CollaboratorAuthor

    We will also need a stable order, so it may require an orderBy.

    Maybe default to ordering by the key if an explicit orderBy isn't added? I'd assume that the item that's found would change if the order changes so either people are explicit about the order, etc. or they're accepting things potentially moving around a bit.

  5. samwillis commented on Jun 17, 2025

    @samwillis
    Collaborator

    Maybe default to ordering by the key if an explicit orderBy isn't added

    orderBy adds overhead... maybe we can just document that the user should provide a stable order if they expect more than one result. I can see fineOne being mostly used for UI screens where there is only ever one result - a filter by PK.

    internally the query returns a CompiledQuery object, that has a .result - maybe when there is a fineOne we keep the internal collection, but .result is resultCollection[0] rather than resultCollection.

    It will need some jiggery pokery on the types of useLiveQuery to ensure that when there is a fineOne it not an array. Very doable.

  6. moved this from Todo to No status in 0.1.0 releaseon Jun 17, 2025
  7. kevin-dp commented on Jul 24, 2025

    @kevin-dp
    Contributor

    What's the status of this?
    This issue #192 was related and got fixed by this PR: #155. Does that simplify the implementation of this feature?

  8. KyleAMathews commented on Jul 24, 2025

    @KyleAMathews
    CollaboratorAuthor

    What's the status of this?

    No one has looked further at it — if you want to take a crack at implementing it, it'd be a nice DX improvement for sure for people!

  9. evanheckert commented on Oct 9, 2025

    @evanheckert

    Coming from Django, they have a few ways to get there.

    Django QuerySet methods that return a single model instance:

    • .get() - Retrieves exactly one object matching the query; raises DoesNotExist if none, MultipleObjectsReturned if more than one.
    • .first() - Returns the first object in the queryset, or None if empty.
    • .last() - Returns the last object in the queryset, or None if empty.
    • .earliest() - Returns the earliest object according to the model’s get_latest_by Meta option or a given field.
    • .latest() - Returns the latest object according to the model’s get_latest_by Meta option or a given field.

    latest()/earliest() for a given date field is accomplished by groupBy() with max()/min(), but that's just returning the latest date value, not the record that happens to be the latest/earliest. Also, I'd love to be able to use :

    • groupBy() --> sortBy() --> first().
  10. evanheckert commented on Oct 25, 2025

    @evanheckert

    I noticed findOne() is now mentioned in the docs, but typescript is not having it (just resolves to never) in latest.

    {
        "@electric-sql/client": "^1.1.0",
        "@electric-sql/react": "^1.0.15",
        ...
        "@tanstack/electric-db-collection": "^0.1.38",
        "@tanstack/query-core": "^5.90.5",
        "@tanstack/query-db-collection": "^0.2.36",
        "@tanstack/react-db": "^0.1.36",
        ...
        "zod": "^4.1.12"
        "react": "^19.2.0",
        "react-dom": "^19.2.0",
        "vite": "^7.1.12",
        ...
        "babel-plugin-react-compiler": "^1.0.0",
        "typescript": "^5.9.3",
    }

    Edit: I see it was actually in (#440 ). I'll need to see if I can put together a simple repro.

  11. evanheckert commented on Oct 27, 2025

    @evanheckert

    New day, fresh start to typescript server, and it's working as intended! Can probably close this one @KyleAMathews

    Edit: Turns out it worked sometimes but not when joins were present. In any case, being fixed in #749

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions