Skip to main content
Swift SDK / Exact / Graph Retrieval Alongside semantic query, a session supports deterministic retrieval — exact lookups that run with no embedding and no similarity ranking. Use it when you know precisely which documents you want: fetch by id, filter by metadata, group chunks back into their parent record, and carry a verbatim structured payload alongside the embedded text. All of these run on MossSession and are fully local — no network round trip.
Requires the Moss iOS SDK v0.6.2+ (.package(url: "https://github.com/usemoss/moss", from: "0.6.2")).

Fetch by id (exact, ordered)

getDocs(ids:) returns documents in the exact order requested. Missing ids are skipped (no error, no gap).
Passing nil returns every document (handy for inspection, expensive on large indexes); an empty array returns nothing:

Fetch by metadata (typed filter)

getDocs(where:) returns every document matching a metadata predicate — no query string, no ranking. Build predicates with the typed Filter DSL instead of hand-written JSON:
sortBy orders results by a metadata field (numeric-aware, so "9" < "50"); ascending defaults to true. Omit sortBy for a deterministic id order.

The Filter DSL

Filter values compose, and FilterValue is literal-expressible — pass "shoes", 27, 0.7, or false directly:
Combine with .and / .or (they nest):
If you already have an engine-format filter string, wrap it with .raw. Invalid JSON surfaces as a thrown MossError rather than silently matching everything:
The same typed Filter works on semantic search too — set QueryOptions.filter to restrict a query to matching documents (it takes precedence over the legacy filterJson string):

Group chunks into their parent record

When a logical record (a long document, an article, a transcript) is stored as several sibling chunks that share a parent id, ParentGrouping collapses them into one result — sibling text assembled in orderField order (numeric-aware), the best score kept.
GetDocsOptions is the full-control entry point — ids, filter, sortBy, ascending, and groupByParent in one call. Grouping also works on semantic query via QueryOptions.groupByParent, which collapses sibling hits into one result per record:
For complete records, prefer getDocs(where:…, groupByParent:) — it groups over the full matching set. On the semantic query path, grouping over-fetches candidates and returns topK records, but a record whose siblings fall outside the fetched window may still be partially assembled. Raise topK if you need wider coverage there.

Verbatim structured payload

Each document can carry an opaque payload stored and returned unchanged — never embedded, never searched. It’s the place for the structured record behind the embedded text (the source row, the full object, anything Codable). Write it from any Encodable with the structured: initializer:
Read it back, decoded to your type, from either a fetch or a query hit:
decodedPayload(_:) returns nil when a document has no payload. The raw string is also available as DocumentInfo.payload / QueryResult.payload. Indexes written before a payload was attached load with payload == nil — no migration, no format break.

Mixing exact and semantic

There’s no blended call — run the two and combine client-side. A common pattern: semantic query to rank candidates, then getDocs(ids:) to pull the exact, fully-populated records (with payloads) for the winners: