Skip to Content
DocsGame ServerGlobal Collection

Managing Global Collection Data

This guide explains how to manage collection data in Agent8. Collections provide a structured way to store and retrieve persistent data—like chat histories, leaderboards, or game records—that can be queried and paginated as needed.

Understanding Collections

Collections in Agent8 are powered by Firestore, offering a simple interface to add, retrieve, update, and delete items. Each collection is uniquely identified and can hold multiple items, making it ideal for scalable data management.

Collections are best used for data that requires querying or pagination, such as chat logs, rankings, or other game records.

Server API

  • $global.getCollectionItems(collectionId: string, options?: CollectionOptions): Promise<Item[]>
    Retrieves multiple items from a collection based on filtering, sorting, and pagination options.

  • $global.getCollectionItem(collectionId: string, itemId: string): Promise<Item>
    Retrieves a single item from a collection using its unique ID.

  • $global.countCollectionItems(collectionId: string, options?: CollectionOptions): Promise<number>
    Retrieves number of items from a collection based on filtering, sorting, and pagination options.

  • $global.addCollectionItem(collectionId: string, item: any): Promise<Item>
    Adds a new item to the specified collection and returns the added item with its unique identifier.

  • $global.updateCollectionItem(collectionId: string, item: any): Promise<Item>
    Updates an existing item in a collection and returns the updated item.

  • $global.deleteCollectionItem(collectionId: string, itemId: string): Promise<{ __id: string }>
    Deletes an item from the collection and returns a confirmation containing the deleted item’s ID.

  • $global.deleteCollection(collectionId: string): Promise<string>
    Deletes the collection and returns a confirmation containing the deleted collection ID.

server.js
class Server { async addCollectionItem(collectionId, item) { return await $global.addCollectionItem(collectionId, item); } async updateCollectionItem(collectionId, item) { return await $global.updateCollectionItem(collectionId, item); } async deleteCollectionItem(collectionId, itemId) { return await $global.deleteCollectionItem(collectionId, itemId); } async getCollectionItems(collectionId, options = {}) { return await $global.getCollectionItems(collectionId, options); } async getCollectionItem(collectionId, itemId) { return await $global.getCollectionItem(collectionId, itemId); } async countCollectionItems(collectionId, options = {}) { return await $global.countCollectionItems(collectionId, options); } }

Client API

subscriptions

  • server.subscribeGlobalCollection(collectionId: string, ({ items, changes }: { items: any[], changes: { op: 'add'|'update'|'delete'|'deleteAll', items: any[]} }) => {}): UnsubscribeFunction

hooks

  • const { items } = useGlobalCollection(collectionId)

Subscribe to Global Collection Updates

import { useGameServer } from "@agent8/gameserver"; import { useEffect } from "react"; function CollectionComponent() { const { connected, server } = useGameServer(); const collectionId = "my-collection"; useEffect(() => { if (!connected) return; const unsubscribe = server.subscribeGlobalCollection( collectionId, ({ items, changes }) => { console.log("all items", items); console.log("Updated items:", changes.items); // Handle different operations if (changes.op === "add") { // Handle added items } else if (changes.op === "update") { // Handle updated items } else if (changes.op === "delete") { // Handle deleted items } } ); // Cleanup subscription when component unmounts return () => unsubscribe(); }, [connected, server, collectionId]); return <div>Collection Component</div>; }

Sync Collection with React Hooks

To synchronize collections in real-time using hooks:

import { useGlobalCollection } from "@agent8/gameserver"; function CollectionDisplay() { const collectionId = "my-collection"; const { items } = useGlobalCollection(collectionId); return ( <div> <h2>Collection Items</h2> <ul> {items.map((item) => ( <li key={item.__id}>{JSON.stringify(item)}</li> ))} </ul> </div> ); }

The useGameCollection hook automatically handles subscriptions and unsubscriptions, making it the recommended approach for React applications.


Example 1: Chat

server.js
class Server { async sendChat(message) { const chatItem = { sender: $sender.account, message, timestamp: Date.now(), }; return await $global.addCollectionItem("chats", chatItem); } async deleteChat(id) { const chat = await $global.getCollectionItem("chats", id); if (chat.sender !== $sender.account) { return { error: "Not authorized to delete this message" }; } return await $global.deleteCollectionItem("chats", id); } async getChats() { return await $global.getCollectionItems("chats"); } }
App.tsx
import { useGameServer, useGlobalCollection } from "@agent8/gameserver"; import { useState, useEffect } from "react"; export default function Chat() { const { connected, server } = useGameServer(); const { items: chats } = useGlobalCollection("chats"); const [message, setMessage] = useState(""); useEffect(() => { if (!connected) return; // Optional: Perform additional setup with the collection subscription const unsubscribe = server.subscribeGlobalCollection( "chats", ({ items, changes }) => { // Custom handling if needed beyond useGameCollection } ); return () => unsubscribe(); }, [connected, server]); if (!connected) return <p>Loading...</p>; const handleSend = async () => { if (message.trim()) { await server.remoteFunction("sendChat", [message]); setMessage(""); } }; const handleDelete = async (id) => { await server.remoteFunction("deleteChat", [id]); }; return ( <div> <div> {chats.map((chat) => ( <div key={chat.__id}> <span>{chat.sender}: </span> <span>{chat.message}</span> <button onClick={() => handleDelete(chat.__id)}>Delete</button> </div> ))} </div> <input type="text" value={message} onChange={(e) => setMessage(e.target.value)} onKeyDown={(e) => e.key === "Enter" && handleSend()} /> <button onClick={handleSend}>Send</button> </div> ); }
Last updated on