elasticsearch_dsl/search/sort/
nested_field_sort.rs

1use crate::{util::ShouldSkip, Query};
2
3/// Sorts search hits by fields that are inside one or more nested objects.
4///
5/// <https://www.elastic.co/guide/en/elasticsearch/reference/current/sort-search-results.html#nested-sorting>
6#[derive(Default, Clone, PartialEq, Debug, Serialize)]
7pub struct NestedFieldSort {
8    path: String,
9
10    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
11    filter: Option<Query>,
12
13    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
14    max_children: Option<u32>,
15
16    #[serde(skip_serializing_if = "ShouldSkip::should_skip")]
17    nested: Option<Box<NestedFieldSort>>,
18}
19
20impl NestedFieldSort {
21    /// Creates an instance of [NestedFieldSort]
22    pub fn path<T>(path: T) -> Self
23    where
24        T: ToString,
25    {
26        Self {
27            path: path.to_string(),
28            filter: None,
29            max_children: None,
30            nested: None,
31        }
32    }
33
34    /// A filter that the inner objects inside the nested path should match with in order for its field values to be taken into account by sorting.
35    pub fn filter<T>(mut self, filter: T) -> Self
36    where
37        T: Into<Option<Query>>,
38    {
39        self.filter = filter.into();
40        self
41    }
42
43    /// The maximum number of children to consider per root document when picking the sort value.
44    pub fn max_children(mut self, max_children: u32) -> Self {
45        self.max_children = Some(max_children);
46        self
47    }
48
49    /// Same as top-level nested but applies to another nested path within the current nested object.
50    pub fn nested(mut self, nested: NestedFieldSort) -> Self {
51        self.nested = Some(Box::new(nested));
52        self
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use crate::{util::assert_serialize, Query};
60
61    #[test]
62    fn serialization() {
63        // custom tests
64        assert_serialize(NestedFieldSort::path("offer"), json!({  "path": "offer" }));
65
66        assert_serialize(
67            NestedFieldSort::path("offer").max_children(2),
68            json!({  "path": "offer", "max_children": 2 }),
69        );
70
71        // based on examples from Elasticsearch documentation
72        assert_serialize(
73            NestedFieldSort::path("offer").filter(Query::term("offer.color", "blue")),
74            json!({
75               "path": "offer",
76               "filter": {
77                  "term" : { "offer.color" : {"value": "blue"} }
78               }
79            }),
80        );
81
82        assert_serialize(
83            NestedFieldSort::path("parent")
84                .filter(Query::range("parent.age").gte(21))
85                .nested(
86                    NestedFieldSort::path("parent.child")
87                        .filter(Query::r#match("parent.child.name", "matt")),
88                ),
89            json!({
90                "path": "parent",
91                "filter": {
92                   "range": {"parent.age": {"gte": 21}}
93                },
94                "nested": {
95                   "path": "parent.child",
96                   "filter": {
97                      "match": {"parent.child.name": {"query": "matt"}}
98                   }
99                }
100            }),
101        );
102    }
103}