> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sublay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Fetching Entities

> Loading, paginating, sorting, and managing entities in a list

`useEntityList` is the main hook for building entity feeds. Each list is identified by a `listId`, allowing multiple independent lists on the same page.

## Basic Setup

```tsx theme={null}
import { useEntityList } from "@sublay/react-js";
import { useEffect } from "react";

function Feed() {
  const { entities, loading, hasMore, fetchEntities, loadMore } = useEntityList({
    listId: "main-feed",
  });

  useEffect(() => {
    fetchEntities(
      {},                         // filters (empty = no filters)
      { sortBy: "hot" },          // sort config
      { limit: 20, include: ["user"] } // list config
    );
  }, []);

  return (
    <>
      {loading && <p>Loading...</p>}
      {entities.map((entity) => (
        <div key={entity.id}>{entity.title}</div>
      ))}
      {hasMore && (
        <button onClick={loadMore} disabled={loading}>
          Load more
        </button>
      )}
    </>
  );
}
```

## `fetchEntities` Signature

```ts theme={null}
fetchEntities(
  filters: Partial<EntityListFilters>,
  sort?: Partial<EntityListSort>,
  config?: EntityListConfig,
  options?: EntityListFetchOptions
) => void
```

### Filters

| Param | Type | Description |
| - | - | - |
| `timeFrame` | `"day" \| "week" \| "month" \| "year"` | Filter by age |
| `userId` | `string` | Filter to a specific user's entities |
| `followedOnly` | `boolean` | Only show entities from users the current user follows |
| `keywordsFilters` | `KeywordsFilters` | Filter by keywords |
| `titleFilters` | `TitleFilters` | Filter by title content |
| `contentFilters` | `ContentFilters` | Filter by body content |
| `attachmentsFilters` | `AttachmentsFilters` | Filter by attachments data |
| `locationFilters` | `LocationFilters` | Filter by geographic proximity |
| `metadataFilters` | `MetadataFilters` | Filter by metadata fields |

### Sort config

| Param | Type | Description |
| - | - | - |
| `sortBy` | `"createdAt" \| "hot" \| "top" \| "controversial" \| "metadata.field"` | Sort algorithm |
| `sortByReaction` | `"upvote" \| "downvote" \| "like" \| "love" \| "wow" \| "sad" \| "angry" \| "funny"` | Which reaction `top` ranks by; only sent while `sortBy` is `"top"` |
| `sortDir` | `"asc" \| "desc"` | Sort direction |
| `sortType` | `"auto" \| "numeric" \| "text" \| "boolean" \| "timestamp"` | Type hint for metadata sorts |

### List config

| Param | Type | Description |
| - | - | - |
| `limit` | `number` | Results per page. Default: `10` |
| `sourceId` | `string` | Filter to a specific source section |
| `spaceId` | `string` | Filter to a specific space |
| `include` | `string \| EntityInclude[]` | Populate related data: `"user"`, `"space"`, `"topComments"`, `"saved"`, `"files"`, `"grants"` |
| `topCommentsLimit` | `number` | With `"topComments"` included: top comments per entity. Server default `1`, max `5`. Not sent when `include` doesn't contain `"topComments"` |
| `topCommentsSortByReaction` | `ReactionType` | With `"topComments"` included: the reaction whose raw count ranks them. Server default `"upvote"`. Not sent when `include` doesn't contain `"topComments"` |

Each `fetchEntities` call sets the whole list config: a field you leave out goes back to its default (`limit` 10, the others unset) rather than keeping the value from the previous call, and `loadMore` uses the config of the last `fetchEntities` call.

### Fetch options

| Param | Type | Description |
| - | - | - |
| `fetchImmediately` | `boolean` | Skip debounce and fetch right away |
| `clearImmediately` | `boolean` | Clear the current list before fetching |
| `resetFilters` | `boolean` | Reset all filters to defaults before applying new ones |
| `resetSort` | `boolean` | Reset sort to defaults before applying new sort |

## Hot Ranking

`sortBy: "hot"` ranks entities by a score that combines engagement and age:

* **Engagement.** Upvotes, comments and shares raise the score; downvotes lower it. The total is weighed against the entity's views, so an entity that draws a reaction from more of its viewers ranks higher.
* **Age.** The whole score decays over time, so newer entities overtake older ones. Entities also get a small boost during their first 6 hours.
* **Ties.** Entities with equal scores are ordered newest first.

Scores are recalculated when an entity is fetched, at most once every 5 minutes. An entity that hasn't been loaded in a while is rescored on its next fetch.

### Feed decay

How fast scores decay is a per-project setting: **Settings → SDK → Feed Decay** in the [dashboard](https://dash.sublay.io). It ranges from 6 hours to 1 month and defaults to 5 days. After one period, an entity's score has dropped to about 37% of what it would otherwise be.

Choose it based on how often new entities arrive:

| New entities arrive | Suggested decay |
| - | - |
| Many per hour | 6–12 hours |
| A few to dozens per day | 5 days – 1 week |
| Less than one per day | 2 weeks – 1 month |

<Warning>
  A decay that is too short for your posting volume makes every entity's score drop to almost nothing within a couple of days. Engagement then stops affecting the order, and `hot` behaves like newest first.
</Warning>

## Infinite Scroll

Call `loadMore()` to append the next page. The hook tracks pagination state internally.

```tsx theme={null}
<button onClick={loadMore} disabled={loading || !hasMore}>
  Load More
</button>
```

`hasMore` reflects the value returned by the server, based on the total item count.

## Creating Entities Within a List

`createEntity` creates an entity and automatically inserts it into the list:

```tsx theme={null}
const { createEntity } = useEntityList({ listId: "my-feed" });

await createEntity({
  title: "New Post",
  content: "Hello!",
  insertPosition: "first", // "first" or "last"
});
```

## Deleting Entities From a List

`deleteEntity` removes an entity from both the server and the local list state:

```tsx theme={null}
const { deleteEntity } = useEntityList({ listId: "my-feed" });

await deleteEntity({ entityId: "ent_abc123" });
```

## Sorting by Metadata

You can sort by any metadata field using the `metadata.fieldName` syntax:

```tsx theme={null}
fetchEntities(
  {},
  { sortBy: "metadata.price", sortType: "numeric", sortDir: "asc" }
);
```

<Note>
  Metadata field names must contain only alphanumeric characters and underscores.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.