Collections
1. Create using schema
defmodule MyApp.Listings.Company do
use Ecto.Schema
@behaviour ExTypesense
defimpl Jason.Encoder, for: __MODULE__ do
def encode(value, opts) do
value
|> Map.take([:companies_id, :name, :country])
|> Enum.map(fn {key, val} ->
if key === :companies_id, do: {key, Map.get(value, :id)}, else: {key, val}
end)
|> Enum.into(%{})
|> Jason.Encode.map(opts)
end
end
schema "companies" do
field(:name, :string)
field(:country, :string)
field(:companies_id, :integer, virtual: true)
end
@impl ExTypesense
def get_field_types do
name = __MODULE__.__schema__(:source)
primary_field = name <> "_id"
%{
name: name,
default_sorting_field: primary_field,
fields: [
%{name: primary_field, type: "int32"},
%{name: "name", type: "string"},
%{name: "country", type: "string"}
]
}
end
end
2. Create the collection in iex -S mix
shell
iex> ExTypesense.create_collection(Company)
{:ok,
%OpenApiTypesense.CollectionResponse{
created_at: 1234567890,
default_sorting_field: "companies_id",
fields: [...],
name: "companies",
num_documents: 0,
symbols_to_index: [],
token_separators: []
}
}
Create using map
iex> schema =
...> %{
...> name: "companies",
...> fields: [
...> %{name: "company_name", type: "string"},
...> %{name: "companies_id", type: "int32"},
...> %{name: "country", type: "string", facet: true}
...> ],
...> default_sorting_field: "companies_id"
...> }
iex> ExTypesense.create_collection(schema)
{:ok,
%OpenApiTypesense.CollectionResponse{
created_at: 1234567890,
default_sorting_field: "companies_id",
fields: [...],
name: "companies",
num_documents: 0,
symbols_to_index: [],
token_separators: []
}
}
List collections
iex> ExTypesense.list_collections()
{:ok, []}
Clone collections
iex> ExTypesense.clone_collection("companies", "new_companies")
{:ok,
%OpenApiTypesense.CollectionResponse{
created_at: 1234567890,
default_sorting_field: "companies_id",
fields: [...],
name: "new_companies",
num_documents: 0,
symbols_to_index: [],
token_separators: []
}
}
Get collection
iex> ExTypesense.get_collection(MyApp.Context.Company)
{
:ok,
%OpenApiTypesense.CollectionResponse{
name: "companies",
fields: [...],
default_sorting_field: "company_id",
created_at: 1737896943,
enable_nested_fields: false,
num_documents: 0,
symbols_to_index: [],
token_separators: [],
voice_query_model: nil
}
}
Update a collection
iex> schema =
...> %{
...> fields: [
...> %{name: "country", drop: true},
...> %{name: "company_category", type: "string"},
...> ],
...> }
iex> ExTypesense.update_collection_fields("companies", schema)
{:ok,
%OpenApiTypesense.CollectionUpdateSchema{
"fields" => [
%{name: "country", drop: true},
%{name: "company_category", type: "string"}
]
}
}
Drop a collection
iex> ExTypesense.drop_collection(MyApp.Context.Company)
iex> ExTypesense.drop_collection("companies")
{
:ok,
%OpenApiTypesense.CollectionResponse{
name: "companies",
fields: [...],
default_sorting_field: "company_id",
created_at: 1737895283,
enable_nested_fields: false,
num_documents: 0,
symbols_to_index: [],
token_separators: [],
voice_query_model: nil
}
}
Documents
Indexes multiple documents with Ecto structs
iex> posts = Post |> Repo.all()
iex> ExTypesense.import_documents(Post, posts)
{:ok, [%{"success" => true}, %{"success" => true}]}
Delete a document by query
iex> opts = [
...> filter_by: "num_employees:>100",
...> batch_size: 100
...> ]
iex> ExTypesense.delete_documents_by_query(Employee, opts)
{:ok, %OpenApiTypesense.Documents{num_deleted: 1}}
Index a document using map
iex> document = %{
...> collection_name: "companies",
...> company_name: "Malwart",
...> companies_id: 1001,
...> country: "US"
...> }
iex> ExTypesense.index_document(document)
{:ok,
%{
id: "0",
...
}
}
Index a document from an Ecto schema
iex> post = Post |> limit(1) |> Repo.one()
iex> ExTypesense.index_document(post, :create)
{:ok,
%{
id: "12",
...
}
}
Indexes multiple documents with maps
iex> documents = [
...> %{
...> company_name: "Industrial Mills, Co.",
...> doc_companies_id: 990,
...> country: "US"
...> },
...> %{
...> company_name: "Washing Machine, Inc.",
...> doc_companies_id: 10,
...> country: "US"
...> }
...> ]
iex> ExTypesense.import_documents("companies", documents)
{:ok, [%{"success" => true}, %{"success" => true}]}
update using Ecto struct
iex> post = Post |> limit(1) |> Repo.one()
iex> ExTypesense.update_document(post, 0)
{:ok,
%{
id: "0",
collection_name: "posts",
posts_id: 34,
title: "test",
description: "lorem ipsum"
}
}
Delete a document
iex> ExTypesense.delete_document(Post, 0)
{:ok,
%{
id: "0",
collection_name: "posts",
posts_id: 34,
title: "test",
description: "lorem ipsum"
}
}
How to use search
Search using module name (atom)
iex> params = %{q: "test", query_by: "title"}
iex> ExTypesense.search(Post, params)
{:ok,
%OpenApiTypesense.SearchResult{
found: 0,
conversation: nil,
facet_counts: [],
found_docs: nil,
grouped_hits: nil,
hits: [...]
out_of: 0,
page: 1,
request_params: %{q: "test", collection_name: "posts", first_q: "test", per_page: 10},
search_cutoff: false,
search_time_ms: 5
}
}
Search returns Ecto query
iex> params = %{q: "test", query_by: "title"}
iex> ExTypesense.search_ecto(Post, params)
{:ok,
%OpenApiTypesense.SearchResult{
found: 0,
conversation: nil,
facet_counts: [],
found_docs: nil,
grouped_hits: nil,
hits: [...]
out_of: 0,
page: 1,
request_params: %{q: "test", collection_name: "posts", first_q: "test", per_page: 10},
search_cutoff: false,
search_time_ms: 5
}
}
Multi search
iex> searches = [
...> %{collection: "companies", q: "Loca Cola"},
...> %{collection: Company, q: "Burgler King"},
...> %{collection: Catalog, q: "umbrella"}
...> ]
iex> ExTypesense.multi_search(searches)
{:ok,
[
{
%{"facet_counts" => [], "found" => 0, "hits" => [], ...},
%{"facet_counts" => [], "found" => 0, "hits" => [], ...},
%{"facet_counts" => [], "found" => 0, "hits" => [], ...},
}
]
}
Search using collection name (string)
iex> params = %{q: "test", query_by: "title"}
iex> ExTypesense.search("posts", params)
{:ok,
%OpenApiTypesense.SearchResult{
found: 2,
conversation: nil,
facet_counts: [],
found_docs: nil,
grouped_hits: nil,
hits: [...]
out_of: 4,
page: 1,
request_params: %{q: "test", collection_name: "posts", first_q: "test", per_page: 10},
search_cutoff: false,
search_time_ms: 5
}
}