Cheatsheet Example

View Source

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"
  }
}

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
  }
}
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
  }
}