@sinequa/atomic

Result anatomy

What a search returns — the documents, the facet counts, and the one field to check before trusting an empty result.

A search response carries the documents and the facet counts in one object. There is no second request for aggregations, and no assembling to do on your side.

Check $error first

An empty result has two very different causes, and they arrive identically: no records, rowCount: 0.

the first thing to read
if (result.$error) {
  // The request failed. Nothing else on this object was received.
  showError(result.$error.message);
} else if (result.rowCount === 0) {
  // The corpus legitimately matched nothing.
  showEmptyState();
}

$error is set by the client and never by the server — it exists precisely so the two can be told apart. Code that reads only records reports "no results" for a backend answering 500 on a malformed filter, which is the hardest kind of bug to notice.

The response

Documents and counts

Prop

Type

Facets, tabs and sorting

Prop

Type

Language features

Present only when the query web service is configured for them, which is why most are optional.

Prop

Type

Article — one document

Article declares the columns every Sinequa index has:

GroupFields
Identityid, rank, databasealias, containerid
Displaytitle, displayTitle (with highlight markup), filename, fileext, docformat, doctype, size, modified, treepath, authors, collection, connector, flags
Linksurl1, url2, originalUrl, pdfUrl, thumbnailUrl
Relevanceglobalrelevance, documentweight, relevantExtracts (HTML), extracts, matchlocations, matchingpartnames, termspresence
Neuralmatchingpassages, $hasPassages
Securityaccesslists
Duplicatesnearhash, exacthash, groupcount, $isDuplicate, $duplicateCount
Client-side$selected, $page

Everything else your index holds is not on the type. Custom metadata — sourcestr1, a mapped department — exists on the object but is not declared, and its value may be a string, a comma-separated string, an array, or an array of { display, value } objects depending on the column.

getMetadata normalises all of those to string[]:

Rendering a hit list, custom metadata included
src/render.ts
import { createAtomicClient, getMetadata, getMetadataWithValues } from "@sinequa/atomic";
import type { Article, Result } from "@sinequa/atomic";

const client = createAtomicClient({
  app: "<your-app>",
  backendUrl: "https://<your-sinequa-server>",
});

await client.initializeConfig();
await client.auth.login();

const result: Result = await client.api.query.search({
  name: "<your-query>",
  text: "quarterly report",
  pageSize: 10,
});

if (result.$error) throw result.$error;

for (const record of result.records) {
  console.log(describe(record));
}

function describe(record: Article) {
  // Declared columns: read them directly.
  const parts = [record.title, record.docformat, `${record.size} bytes`];

  // Custom columns: always a string[], whatever shape the server sent.
  const departments = getMetadata(record, "department");
  if (departments.length) parts.push(departments.join(" / "));

  // When you need the value behind the label — to filter on it, typically.
  for (const { display, value } of getMetadataWithValues(record, "department")) {
    console.log(`  facet on ${value}, shown as ${display}`);
  }

  // The highlighted snippet is HTML: render it as such, or strip it.
  if (record.relevantExtracts) parts.push(record.relevantExtracts);

  return parts.join(" — ");
}

AggregateResult — a different response

A query sent with action: "aggregate" answers with four keys and nothing else:

the whole type
type AggregateResult = {
  id: string;
  queryName: string;
  aggregations: (Aggregation | TreeAggregation)[];
  attributes: Attributes;
};

No records, no rowCount, no page, no tab. Casting one to Result makes twelve absent fields look present, and arithmetic on them yields NaN — where every comparison is false, so a response with no pagination reads exactly like one on its last page.

The $ convention

A $-prefixed field is added by the client, never sent by the server:

FieldOnMeaning
$errorResultThe request failed; nothing else was received.
$selectedArticle, AggregationItemYour selection state, for you to maintain.
$pageArticleWhich page this document came from, when accumulating pages.
$hasMoreAggregationMore items are available than were returned.
$path, $level, $openedTreeAggregationNodeComputed when a tree is expanded.
$isDuplicate, $duplicateCountArticleDuplicate grouping.
$hasPassagesArticleWhether neural passages were attached.

Pitfalls

What's next

On this page