typesense / typesense

Open Source alternative to Algolia + Pinecone and an Easier-to-Use alternative to ElasticSearch ⚡ 🔍 ✨ Fast, typo tolerant, in-memory fuzzy Search Engine for building delightful search experiences

Home Page:https://typesense.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Joins] Having issue with the querying

webdeveloper20213 opened this issue · comments

I am currently using the typesense@1.8.0-7 version the one that supports joins and all

I have two tables : restaurants and dishes

there is one to many relationship between restaurants and dishes (one restaurant can have multiple dishes)


let searchParameters = {
      q: "*",
      query_by: "*",
      filter_by: `$restaurants(id:="${restaurantId}")`,
      page: page,
      per_page: pageSize,
      sort_by: "",
};
    
    const result = await typesense.collections("dishes").documents().search(searchParameters);

schemas are like this

dishes : {
{ "name" : "restaurant_id", "reference": "restaurants.id" }
}

I know that I can do something like this easily

filter_by: restaurant_id:"${restaurantId}"

but in some scenario we need to do something like this
filter_by: $restaurants(id:="${restaurantId}"),

I am getting this error

{
"message": "Failed to apply reference filter on restaurants collection: Could not find any field in restaurants referencing the collection dishes."
}

seems here relationship is different instead of dishes -> restaurants

here it's restaurants -> dishes (1 -> n)

any solution ?

@jasonbosco @kishorenc

@webdeveloper20213 If you could elaborate on

but in some scenario we need to do something like this
filter_by: $restaurants(id:="${restaurantId}"),

I'll be able to help you better with your use-case.

My best guess is you're trying to pull the related restaurant's info. For that, you can simply specify:

include_fields: $restaurants(*)

ok so instead of the filter_by I have to use the include_fields

but here I have one question that in one document for here we have restaurants in that I want to pull only those records where restaurants.id = restaurantId

$restaurants(id:="${restaurantId}") that's why I was trying this.
@happy-san

Can you share your collection schemas?

{
  "created_at": 1710756719,
  "default_sorting_field": "created_at",
  "enable_nested_fields": false,
  "fields": [
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "name",
      "optional": false,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "created_by",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "restaurant_id",
      "optional": true,
      "reference": "restaurants.id",
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "created_at",
      "optional": false,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "updated_at",
      "optional": false,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "deleted_at",
      "optional": true,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "is_active",
      "optional": true,
      "sort": true,
      "type": "bool"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "media_id",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "order_id",
      "optional": true,
      "sort": true,
      "type": "float"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "is_copied",
      "optional": true,
      "sort": true,
      "type": "bool"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "copied_from",
      "optional": true,
      "sort": false,
      "type": "string"
    }
  ],
  "name": "dishes",
  "num_documents": 7,
  "symbols_to_index": [],
  "token_separators": []
}
{
  "created_at": 1710747871,
  "default_sorting_field": "created_at",
  "enable_nested_fields": false,
  "fields": [
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "name",
      "optional": false,
      "sort": false,
      "type": "string"
    },
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "restaurant_custom_id",
      "optional": false,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "business_name",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "address",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "description",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "fiscal_invoice",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "telephone",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "cell_phone",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "email",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "latitude",
      "optional": true,
      "sort": true,
      "type": "float"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "longitude",
      "optional": true,
      "sort": true,
      "type": "float"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "logo",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "pin",
      "optional": true,
      "sort": true,
      "type": "int32"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "delivery_range",
      "optional": true,
      "sort": true,
      "type": "int32"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "colour_palate",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "executive_chef",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "extra_information",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "is_varified",
      "optional": false,
      "sort": true,
      "type": "bool"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "is_open",
      "optional": false,
      "sort": true,
      "type": "bool"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "created_at",
      "optional": false,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "updated_at",
      "optional": false,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "executive_chef_user_id",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "created_by",
      "optional": true,
      "sort": false,
      "type": "string"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "city_id",
      "optional": true,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "state_id",
      "optional": true,
      "sort": true,
      "type": "int64"
    },
    {
      "facet": false,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "country_id",
      "optional": true,
      "sort": true,
      "type": "int64"
    }
  ],
  "name": "restaurants",
  "num_documents": 246,
  "symbols_to_index": [],
  "token_separators": []
}

@happy-san

This should help you achieve it.

filter_by: `restaurant_id:"${restaurantId}"`,

I have already mentioned this in my original question, I know about this syntax but I want to know...

about joins like we have in SQL

above pasted schemas are representations of both restaurants and dishes tables

and there is one to many relation between restaurants and dishes (one restaurant can have many dishes)

with SQL query

select * from dishes d inner join restaurants r on d.restaurant_id = r.id;

something like this in typesense

this was the intention behind the $restaurants(id:="${restaurantId}")

with dish listing I want it's restaurants object too that is what I was asking.

[ { dish_id:1, name, ... , restaurant: {} //whole restaurant object ]}

I am asking about this kind of filter where I can fetch single record when we have one to many relationship between the different schemas

how to achieve this.

hope this helps.
@happy-san

Let me try this example locally. I'll get back to you.

no problem thank you

I tried this example

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "restaurants",
  "fields": [
    {"name": "id", "type": "string"},
    {"name": "rating", "type": "int32"}
  ]
}'

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "dishes",
  "fields": [
    {"name": "id", "type": "string"},
    {"name": "restaurant_id", "type": "string", "reference": "restaurants.id"},
    {"name": "dish_price", "type": "float"}
  ] 
}'

curl "http://localhost:8108/collections/restaurants/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"id": "restaurant_a","rating": 3}
	{"id": "restaurant_b","rating": 4}
	{"id": "restaurant_c","rating": 5}'

curl "http://localhost:8108/collections/dishes/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"id": "dish_a","dish_price": 143,"restaurant_id": "restaurant_a"}
	{"id": "dish_b","dish_price": 73.5,"restaurant_id": "restaurant_b"}
	{"id": "dish_c","dish_price": 75,"restaurant_id": "restaurant_a"}
	{"id": "dish_d","dish_price": 140,"restaurant_id": "restaurant_b"}
	{"id": "dish_e","dish_price": 5000,"restaurant_id": "restaurant_c"}'


curl 'http://localhost:8108/multi_search' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '
  {"searches":[{"collection":"dishes","q":"*","filter_by":"$restaurants(id:=restaurant_a || rating: 5)"}]}' | jq

It returns

{
  "results": [
    {
      "facet_counts": [],
      "found": 3,
      "hits": [
        {
          "document": {
            "dish_price": 5000,
            "id": "dish_e",
            "restaurant_id": "restaurant_c",
            "restaurants": {
              "id": "restaurant_c",
              "rating": 5
            }
          },
          "highlight": {},
          "highlights": []
        },
        {
          "document": {
            "dish_price": 75,
            "id": "dish_c",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        },
        {
          "document": {
            "dish_price": 143,
            "id": "dish_a",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        }
      ],
      "out_of": 5,
      "page": 1,
      "request_params": {
        "collection_name": "dishes",
        "first_q": "*",
        "per_page": 10,
        "q": "*"
      },
      "search_cutoff": false,
      "search_time_ms": 0
    }
  ]
}

Your example should've worked too. If not, I suspect you might be on an old RC build. You can try it with the latest build.

my current typesense version is [1.8.0-7] got it through 1.8.0-7

or we have new version of typesense again ?

I have tried your above query didn't got the any result in docs

query:

let searchParameters = {
      q: "*",
      query_by: "*",
      filter_by: `restaurant_id:"${restaurantId}"`,
      include_fields: `$restaurants("*")`,
      page: page,
      per_page: pageSize,
      // sort_by: "",
    };

    const result = await typesense
      .collections("dishes")
      .documents()
      .search(searchParameters);

result:
      {
    "facet_counts": [],
    "found": 4,
    "hits": [
        {
            "document": {},
            "highlight": {},
            "highlights": []
        },
        {
            "document": {},
            "highlight": {},
            "highlights": []
        },
        {
            "document": {},
            "highlight": {},
            "highlights": []
        },
        {
            "document": {},
            "highlight": {},
            "highlights": []
        }
    ],
    "out_of": 7,
    "page": 1,
    "request_params": {
        "collection_name": "dishes",
        "per_page": 40,
        "q": "*"
    },
    "search_cutoff": false,
    "search_time_ms": 0
}

maybe this is happening because of the version ?
what is the latest version because in npm latest is 1.8.0-7

What version is your Typesense server on?

I have installed typesense@1.8.0-7 which is >= v0.26.0.rc38 typesense server version

typesense@1.8.0-7 this is the version of your typesense client that you're using to connect with the server.
Use this command to find out your typesense server version.

curl "http://localhost:8108/debug"  -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}"

I am directly using the typesense cloud here not the localhost version

Okay. Can you upgrade your cluster to 0.26.0.rc68?

not having any of those options, maybe because I am on free tier ? how can I do that ?

From the dashboard can you try
Cluster Configuration > Modify > Typesense Version

is there any way to have nested joins in the typesense

like for here in this example

let searchParameters = {
      q: `*`,
      query_by: "*",
      filter_by: `$restaurants(id:=${restaurantId})`,
      include_fields: `$restaurants(*)`,
      page: page,
      per_page: pageSize,
      // sort_by: "",
    };

    if (tagFilter.length > 0) {
      const names = tagFilter.map((tag) => tag.id);
      searchParameters.filter_by += ` && $dish_tags(tags_id:=[${names}])`;
      searchParameters.include_fields += ` && $tags(*)`
    }

    const result = await typesense
      .collections("dishes")
      .documents()
      .search(searchParameters);

here I have three collections, dishes, tags, and dish_tags
it's many to many , in dish_tags I have tags_id through it I would be able to access the tags

what is the syntax for nested joins?

I tried this but it doesn't work

$dish_tags(tags_id:=[${ids}] && $tags(id:=[${ids}])) and $dish_tags($tags(id:=[${ids}])
none of these two queries worked how to do it

we are thinking of using the beta version in our production so will we have any issues in future if we upgrade or add new columns in our tables then how to sync data with the typesense or able to insert our data in typesense

can we search in different tables, In joins tables or nested joins tables how can I search for the related or referenced thing through search.

ex: let's say I am searching for the restaurants in dishes collections but in dishes collections I only have restaurant_id with it would I be able to search in the relational table which is restaurants like name

@webdeveloper20213 Can you share the schema of dish_tags and tags collection as well?

we are thinking of using the beta version in our production so will we have any issues in future if we upgrade or add new columns in our tables then how to sync data with the typesense or able to insert our data in typesense

v0.26 version will be released soon so you won't have to use the beta version, Also, we don't support updating reference fields yet. Updating the rest of the fields should not be an issue.

can we search in different tables, In joins tables or nested joins tables how can I search for the related or referenced thing through search.

ex: let's say I am searching for the restaurants in dishes collections but in dishes collections I only have restaurant_id with it would I be able to search in the relational table which is restaurants like name

Not at the moment. This feature will be part of v0.27.

sure,

dish_tags: {
  "created_at": 1711619142,
  "default_sorting_field": "",
  "enable_nested_fields": true,
  "fields": [
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "dish_id",
      "optional": false,
      "reference": "dishes.id",
      "sort": false,
      "stem": false,
      "type": "string"
    },
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "tags_id",
      "optional": false,
      "reference": "tags.id",
      "sort": false,
      "stem": false,
      "type": "string"
    }
  ],
  "name": "dish_tags",
  "num_documents": 4,
  "symbols_to_index": [],
  "token_separators": []
}
tags: {
  "created_at": 1711614130,
  "default_sorting_field": "",
  "enable_nested_fields": true,
  "fields": [
    {
      "facet": true,
      "index": true,
      "infix": false,
      "locale": "",
      "name": "name",
      "optional": false,
      "sort": false,
      "stem": false,
      "type": "string"
    }
  ],
  "name": "tags",
  "num_documents": 4,
  "symbols_to_index": [],
  "token_separators": []
}

I think $dish_tags($tags(id:=[${ids}]) should've worked. Let me try.

I tried this example

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "restaurants",
  "fields": [
    {"name": "id", "type": "string"},
    {"name": "rating", "type": "int32"}
  ]
}'

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "dishes",
  "fields": [
    {"name": "id", "type": "string"},
    {"name": "restaurant_id", "type": "string", "reference": "restaurants.id"},
    {"name": "dish_price", "type": "float"}
  ] 
}'

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "tags",
  "fields": [
    {"name": "id", "type": "string"},
    {"name": "name", "type": "string"},
    {"name": "rating", "type": "int32"}
  ] 
}'

curl -k "http://localhost:8108/collections" -X POST -H "Content-Type: application/json" -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '{
  "name":  "dish_tags",
  "fields": [
    {"name": "dish_id", "type": "string", "reference": "dishes.id"},
    {"name": "tags_id", "type": "string", "reference": "tags.id"}
  ] 
}'

curl "http://localhost:8108/collections/restaurants/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"id": "restaurant_a","rating": 3}
	{"id": "restaurant_b","rating": 4}
	{"id": "restaurant_c","rating": 5}'

curl "http://localhost:8108/collections/dishes/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"id": "dish_a","dish_price": 143,"restaurant_id": "restaurant_a"}
	{"id": "dish_b","dish_price": 73.5,"restaurant_id": "restaurant_b"}
	{"id": "dish_c","dish_price": 75,"restaurant_id": "restaurant_a"}
	{"id": "dish_d","dish_price": 140,"restaurant_id": "restaurant_b"}
	{"id": "dish_e","dish_price": 5000,"restaurant_id": "restaurant_c"}'

curl "http://localhost:8108/collections/tags/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"id":"tag_a", "name": "indian", "rating": 4}
	{"id":"tag_b", "name": "chinese", "rating": 2}
	{"id":"tag_c", "name": "mexican", "rating": 5}
	{"id":"tag_d", "name": "salad", "rating": 3}
	{"id":"tag_e", "name": "bread", "rating": 3}
	{"id":"tag_f", "name": "curry", "rating": 4}'

curl "http://localhost:8108/collections/dish_tags/documents/import?action=create" \
        -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" \
        -H "Content-Type: text/plain" \
        -X POST \
        -d '{"dish_id": "dish_a", "tags_id": "tag_a"}
        {"dish_id": "dish_a", "tags_id": "tag_e"}
	{"dish_id": "dish_b", "tags_id": "tag_c"}
	{"dish_id": "dish_c", "tags_id": "tag_b"}
	{"dish_id": "dish_c", "tags_id": "tag_f"}
	{"dish_id": "dish_d", "tags_id": "tag_c"}
	{"dish_id": "dish_d", "tags_id": "tag_d"}
	{"dish_id": "dish_e", "tags_id": "tag_b"}'

curl 'http://localhost:8108/multi_search' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '
{
  "searches": [
    {
      "collection": "dishes",
      "q": "*",
      "filter_by": "$restaurants(id:=restaurant_a || rating: 5) && $dish_tags($tags(id: [tag_a, tag_c, tag_e, tag_f]))"
    }
  ]
}' | jq

it returns:

{
  "results": [
    {
      "facet_counts": [],
      "found": 2,
      "hits": [
        {
          "document": {
            "dish_price": 75,
            "dish_tags": {
              "dish_id": "dish_c",
              "id": "4",
              "tags": {
                "id": "tag_f",
                "name": "curry",
                "rating": 4
              },
              "tags_id": "tag_f"
            },
            "id": "dish_c",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        },
        {
          "document": {
            "dish_price": 143,
            "dish_tags": [
              {
                "dish_id": "dish_a",
                "id": "0",
                "tags": {
                  "id": "tag_a",
                  "name": "indian",
                  "rating": 4
                },
                "tags_id": "tag_a"
              },
              {
                "dish_id": "dish_a",
                "id": "1",
                "tags": {
                  "id": "tag_e",
                  "name": "bread",
                  "rating": 3
                },
                "tags_id": "tag_e"
              }
            ],
            "id": "dish_a",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        }
      ],
      "out_of": 5,
      "page": 1,
      "request_params": {
        "collection_name": "dishes",
        "first_q": "*",
        "per_page": 10,
        "q": "*"
      },
      "search_cutoff": false,
      "search_time_ms": 0
    }
  ]
}

Nested include/exclude fields is also supported

curl 'http://localhost:8108/multi_search' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '
{
  "searches": [
    {
      "collection": "dishes",
      "q": "*",
      "filter_by": "$restaurants(id:=restaurant_a || rating: 5) && $dish_tags($tags(id: [tag_a, tag_c, tag_e, tag_f]))",
      "include_fields": "$dish_tags($tags(name, rating))",
      "exclude_fields": "$dish_tags(id, dish_id, $tags(id))"
    }
  ]
}' | jq

returns:

{
  "results": [
    {
      "facet_counts": [],
      "found": 2,
      "hits": [
        {
          "document": {
            "dish_price": 75,
            "dish_tags": {
              "tags": {
                "name": "curry",
                "rating": 4
              },
              "tags_id": "tag_f"
            },
            "id": "dish_c",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        },
        {
          "document": {
            "dish_price": 143,
            "dish_tags": [
              {
                "tags": {
                  "name": "indian",
                  "rating": 4
                },
                "tags_id": "tag_a"
              },
              {
                "tags": {
                  "name": "bread",
                  "rating": 3
                },
                "tags_id": "tag_e"
              }
            ],
            "id": "dish_a",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        }
      ],
      "out_of": 5,
      "page": 1,
      "request_params": {
        "collection_name": "dishes",
        "first_q": "*",
        "per_page": 10,
        "q": "*"
      },
      "search_cutoff": false,
      "search_time_ms": 0
    }
  ]
}

You can also specify include strategy like

curl 'http://localhost:8108/multi_search' -X POST -H "X-TYPESENSE-API-KEY: ${TYPESENSE_API_KEY}" -d '
{
  "searches": [
    {
      "collection": "dishes",
      "q": "*",
      "filter_by": "$restaurants(id:=restaurant_a || rating: 5) && $dish_tags($tags(id: [tag_a, tag_c, tag_e, tag_f]))",
      "include_fields": "$dish_tags($tags(name, rating, strategy: merge), strategy:nest_array)",
      "exclude_fields": "$dish_tags(id, dish_id, $tags(id))"
    }
  ]
}' | jq

that returns:

{
  "results": [
    {
      "facet_counts": [],
      "found": 2,
      "hits": [
        {
          "document": {
            "dish_price": 75,
            "dish_tags": [
              {
                "name": "curry",
                "rating": 4,
                "tags_id": "tag_f"
              }
            ],
            "id": "dish_c",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        },
        {
          "document": {
            "dish_price": 143,
            "dish_tags": [
              {
                "name": "indian",
                "rating": 4,
                "tags_id": "tag_a"
              },
              {
                "name": "bread",
                "rating": 3,
                "tags_id": "tag_e"
              }
            ],
            "id": "dish_a",
            "restaurant_id": "restaurant_a",
            "restaurants": {
              "id": "restaurant_a",
              "rating": 3
            }
          },
          "highlight": {},
          "highlights": []
        }
      ],
      "out_of": 5,
      "page": 1,
      "request_params": {
        "collection_name": "dishes",
        "first_q": "*",
        "per_page": 10,
        "q": "*"
      },
      "search_cutoff": false,
      "search_time_ms": 0
    }
  ]
}

Hello,
@jasonbosco
@happy-san
when 0.26 version with proper docs be released? , can you give us a time duration like a month or weeks?

@webdeveloper20213 We are already in code freeze for v0.26. You can find joins related documentation here(only nested and n-way joins are yet to be documented). The release will happen as soon as we finish the documentation process.

Thanks for the help and information, eagerly waiting for the 0.26 release.