Nested queries are a powerful feature of Elasticsearch that allows you to search within nested objects or arrays. This feature is especially useful when working with complex data structures that require deep search capabilities.
WhereNestedObject
This method allows you to query nested objects within an Elasticsearch document. Nested fields are useful when you need to store large arrays of objects without flattening them into a single array or overindexing the parent index.
$posts = BlogPost :: whereNestedObject ( ' comments ' , function ( Builder $query ) {
$query -> where ( ' comments.country ' , ' Peru ' ) -> where ( ' comments.likes ' , 5 );
This will return all the blog posts where the comments field contains an object with the country field set to ‘Peru’ and the likes field set to 5.
You are free to exclude the parent nested field in the closure, for example:
$posts = BlogPost :: whereNestedObject ( ' comments ' , function ( Builder $query ) {
$query -> where ( ' country ' , ' Peru ' ) -> where ( ' likes ' , 5 );
// 'country' points to 'comments.country'
// 'likes' points to 'comments.likes'
WhereNotNestedObject
Similar to whereNestedObject
, this method allows you to query nested objects within an Elasticsearch document. However, it excludes documents that match the specified nested object query .
$posts = BlogPost :: whereNotNestedObject ( ' comments ' , function ( Builder $query ) {
$query -> where ( ' comments.country ' , ' Peru ' );
This will return all the blog posts where there are no comments from Peru
Order By Nested Field
This method allows you to order the results of a query by a nested field. This is useful when you need to sort the results of a query based on a nested field.
Parameters scope: orderByNested($field, $direction = 'asc', $mode = 'min')
$posts = BlogPost :: where ( ' status ' , 5 ) -> orderByNested ( ' comments.likes ' , ' desc ' , ' sum ' ) -> limit ( 5 ) -> get ();
This will return the 5 blog posts with the highest sum of likes in the comments field where the status field is set to 5.
Filtering Nested Values
This method allows you to filter the values of a nested field by passing in a query closure that will be applied to the nested values.
Internally, the package will set an inner_hits
query to get the nested values that match the closure query, and map them to the parent document.
Example:
1. No Filtering:
$posts = BlogPost :: where ( ' status ' , 5 ) -> orderBy ( ' created_at ' ) -> first ();
return example:
"_id" : " 1IiLKG38BCOXW3U9a4zcn " ,
"title" : " My first post " ,
"name" : " Damaris Ondricka " ,
"comment" : " Quia quis facere cupiditate unde natus dolorem. Quia voluptatem in nam occaecati. Veritatis libero neque vitae. " ,
"comment" : " Officia ut dolorem itaque sapiente repellendus consequatur. Voluptas veniam quis eligendi. Aliquid voluptatem reiciendis ut. " ,
"comment" : " Repudiandae rem aspernatur neque molestiae voluptatibus ut aut. Animi dolor id voluptas. Blanditiis a est nobis voluptatem sed sed illum esse. " ,
"country" : " Switzerland " ,
"comment" : " Et deleniti ab cumque nobis ut ullam. Exercitationem qui sequi voluptatem delectus sunt nobis. Vel libero nihil quas inventore omnis. Harum corrupti consequatur quibusdam ut. " ,
"name" : " Mabelle Schinner " ,
"comment" : " Aliquid molestiae quas vitae ipsam neque nam sed. Facere blanditiis repellendus sequi autem. Explicabo cupiditate porro quia animi ut minus tempora ut. " ,
"country" : " Switzerland " ,
$posts = BlogPost :: where ( ' status ' , 5 ) -> queryNested ( ' comments ' , function ( $query ) {
$query -> where ( ' country ' , ' Switzerland ' ); //or comments.country
}) -> orderBy ( ' created_at ' ) -> first ();
returns:
"_id" : " 1IiLKG38BCOXW3U9a4zcn " ,
"title" : " My first post " ,
"comment" : " Repudiandae rem aspernatur neque molestiae voluptatibus ut aut. Animi dolor id voluptas. Blanditiis a est nobis voluptatem sed sed illum esse. " ,
"country" : " Switzerland " ,
"name" : " Mabelle Schinner " ,
"comment" : " Aliquid molestiae quas vitae ipsam neque nam sed. Facere blanditiis repellendus sequi autem. Explicabo cupiditate porro quia animi ut minus tempora ut. " ,
"country" : " Switzerland " ,
$posts = BlogPost :: where ( ' status ' , 5 ) -> queryNested ( ' comments ' , function ( $query ) {
$query -> where ( ' country ' , ' Switzerland ' ) -> orderBy ( ' likes ' );
}) -> orderBy ( ' created_at ' ) -> first ();
returns:
"_id" : " 1IiLKG38BCOXW3U9a4zcn " ,
"title" : " My first post " ,
"name" : " Mabelle Schinner " ,
"comment" : " Aliquid molestiae quas vitae ipsam neque nam sed. Facere blanditiis repellendus sequi autem. Explicabo cupiditate porro quia animi ut minus tempora ut. " ,
"country" : " Switzerland " ,
"comment" : " Repudiandae rem aspernatur neque molestiae voluptatibus ut aut. Animi dolor id voluptas. Blanditiis a est nobis voluptatem sed sed illum esse. " ,
"country" : " Switzerland " ,
$posts = BlogPost :: where ( ' status ' , 5 ) -> queryNested ( ' comments ' , function ( $query ) {
$query -> where ( ' likes ' , ' > ' , 5 );
}) -> orderBy ( ' created_at ' ) -> first ();
returns:
"_id" : " 1IiLKG38BCOXW3U9a4zcn " ,
"title" : " My first post " ,
"comment" : " Repudiandae rem aspernatur neque molestiae voluptatibus ut aut. Animi dolor id voluptas. Blanditiis a est nobis voluptatem sed sed illum esse. " ,
"country" : " Switzerland " ,
"name" : " Mabelle Schinner " ,
"comment" : " Aliquid molestiae quas vitae ipsam neque nam sed. Facere blanditiis repellendus sequi autem. Explicabo cupiditate porro quia animi ut minus tempora ut. " ,
"country" : " Switzerland " ,
$posts = BlogPost :: where ( ' status ' , 5 ) -> queryNested ( ' comments ' , function ( $query ) {
$query -> where ( ' likes ' , ' >= ' , 5 ) -> limit ( 2 );
}) -> orderBy ( ' created_at ' ) -> first ();
returns:
"_id" : " 1IiLKG38BCOXW3U9a4zcn " ,
"title" : " My first post " ,
"name" : " Damaris Ondricka " ,
"comment" : " Quia quis facere cupiditate unde natus dolorem. Quia voluptatem in nam occaecati. Veritatis libero neque vitae. " ,
"comment" : " Repudiandae rem aspernatur neque molestiae voluptatibus ut aut. Animi dolor id voluptas. Blanditiis a est nobis voluptatem sed sed illum esse. " ,
"country" : " Switzerland " ,
Note on Nested limits:
The default max limit for Elasticsearch on nested values when using inner_hits
is 100
. Trying to set a limit higher than that will result in an error.
You can change the limit by setting the max_inner_result_window
value in your Elasticsearch configuration.
Schema :: create ( ' blog_posts ' , function ( IndexBlueprint $index ) {
$index -> nested ( ' comments ' );
$index -> settings ( ' max_inner_result_window ' , 200 );
Then you can:
$posts = BlogPost :: where ( ' status ' , 5 ) -> queryNested ( ' comments ' , function ( $query ) {
$query -> orderByDesc ( ' likes ' ) -> limit ( 200 )
}) -> orderBy ( ' created_at ' ) -> first ();