Search and connect product records
The language tabs use earlier client interfaces. Check SDK versions and connection setup before running them.
Store a product row, embedding and searchable text under the same ID. A schema relationship links the row to its supplier.
Before you run it: The row and its derived edge share the row write. Vector and full-text writes are separate calls, not one cross-model transaction.
Use the tenant-scoped HTTP connection described in the connection notes. In these snippets, ORIGINCHAIN_URL is the origin including https://, T is its tenant ID, and OC_TOKEN is its bearer token. Do not append these routes to a different Connect URL format.
- Save supplier and productRegister the supplier first and link sku-9281 to it.
- Index the productWrite its embedding and text with the same product ID.
- Search for a matchRetrieve a product ID by words or similarity.
- Open product detailsRead its name, price and supplier relationship.
Follow the example
- Register product and supplier schemas.
- Write the row and declared relationship.
- Write the embedding and text with the same ID.
- Query and reconnect results by ID.
Set up the table
Register the target supplier table before the product table. A relationship returns the supplier key; storing a supplier row lets your application also display its name.
Create the supplier used by this product
curl --fail-with-body -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/schemas" \
-H "Authorization: Bearer $OC_TOKEN" -H "Content-Type: text/plain" \
--data-binary @- <<'TOML'
namespace = "shop"
table = "suppliers"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "name"
ty = "str"
TOML
curl --fail-with-body -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/rows/shop.suppliers" \
-H "Authorization: Bearer $OC_TOKEN" -H "Content-Type: application/json" \
-d '{"id":"sup-acme-shoes","name":"Acme Shoes"}'Now register the product definition below. Use a test database where these sample table names are unused.
Push this once with /v1/tenants/<tenant>/schemas before the first write. Note the [[relations]] block - that's what makes the supplier edge automatic.
# shop/products.toml
namespace = "shop"
table = "products"
primary_key = ["id"]
[[columns]]
name = "id"
ty = "str"
required = true
[[columns]]
name = "name"
ty = "str"
required = true
[[columns]]
name = "description"
ty = "str"
[[columns]]
name = "price_cents"
ty = "i64"
[[columns]]
name = "category"
ty = "str"
[[columns]]
name = "supplier_id"
ty = "str"
required = true
[[indexes]]
name = "by_category"
columns = ["category"]
# Declaring supplier_id as a relation makes the row write also
# create a graph edge from this product to its supplier.
[[relations]]
name = "supplied_by"
from_col = "supplier_id"
bidirectional = true
[relations.target]
namespace = "shop"
table = "suppliers"
pk = "id"The row (also writes the supplier edge)
curl -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/rows/shop.products" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "sku-9281",
"name": "Trailblazer 2",
"description": "All-terrain running shoe with carbon-plate forefoot.",
"price_cents": 12900,
"category": "running-shoes",
"supplier_id": "sup-acme-shoes"
}'The embedding
The id here is the same primary key as the row. Same key = same logical product across shapes.
curl -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/vector/shop.products/put" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "sku-9281",
"embedding": [0.0124, -0.0883, 0.0451, /* ... 768 floats ... */],
"dim": 768,
"metric": "cosine",
"metadata": { "category": "running-shoes" }
}'The full-text index
doc_id matches the row's primary key so search results can be joined back to the row.
curl -X POST "$ORIGINCHAIN_URL/v1/tenants/$T/fts/shop.products/description" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"doc_id": "sku-9281",
"text": "Trailblazer 2 all-terrain running shoe with carbon-plate forefoot"
}'The embedding arrays are shortened illustrations. Generate the full vector with your chosen model, match dim to its length, and use that same model when embedding a search question. An embedding is a numeric representation used to compare meaning; OriginChainDB does not generate it in these write calls.
Handle separate writes and retries
The three calls are separate. There is no single "write everything" endpoint. Each call is atomic by itself - the row write either commits or doesn't, the vector put either commits or doesn't. A new SDK call can create a new idempotency key. Check the failed endpoint’s retry contract and reconcile an uncertain outcome before repeating it; the SDK does not make the three operations one transaction.
Important limits and checks
- Forgetting one of the three calls. If you skip the vector put, similarity search won't return this product. If you skip the FTS index, keyword search won't. The row write doesn't fan out to the other shapes.
- Updating one without re-doing the others. If you re-put the row with a new description, the vector and FTS index still point at the old text until you re-put / re-index them too.
- Mismatched IDs. The
idin the row write, the vector put, and the FTSdoc_idmust all be the same string. If they drift, you can't join search hits back to the row. - Writing the supplier edge by hand. Don't. Let the
[[relations]]block do it. There is no edge-write endpoint to call instead — edges are derived from the row write, so a second "write the edge" step is not something you can do, and not something you need to do.
Expected result
Use the word-search pattern with the table and field above, or query the stored vector. A match for sku-9281 should reopen the product row. Check its name, price and supplier ID rather than displaying a similarity score as product data.