# Filtering sub-documents

**URL:** <https://discuss.elastic.co/t/filtering-sub-documents/6917>\
**Category:** Elasticsearch\
**Created:** [March 6, 2012, 5:59pm UTC](https://discuss.elastic.co/t/filtering-sub-documents/6917 "2012-03-06T17:59:30Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Hugo](https://avatars.discourse-cdn.com/v4/letter/h/b38774/32.png) [@Hugo](https://discuss.elastic.co/u/Hugo)\
**Post date:** [March 6, 2012, 5:59pm UTC](https://discuss.elastic.co/t/filtering-sub-documents/6917/1 "2012-03-06T17:59:30Z")

</div>

Hi all,

I have a document structure like this:

{  
"\_index": "building",  
"\_type": "info",  
"\_source": {  
"name": "First building",  
"security\_level": 1,  
"state": 1,  
"description": "first area obs",  
"floors": [  
{  
"description": "First Store",  
"name": "First floor",  
"security\_level": 2  
},  
{  
"description": "Second Store",  
"name": "Second floor",  
"security\_level": 1  
}  
]  
}  
}

and I want to search by floor name/description and/or building  
name/description but omitting the results if the user does not have the  
correct security level.  
For instance if I try to find "First" and my security\_level is 0 I should  
not get any hit, but if my security level is 1 or 2 I should get one hit.  
Also if I try to find "Store" and my security\_level is 0 I should not get  
any hit, but if my security level is 1 or 2 I should get one hit.

I've tried using the following query (for a user with security\_level equal  
to 1) but is does not work because it filters all documents that have one  
or more floors.security\_level equal to 2, even if there are other  
floors.security\_level with 0 or 1 that match the other criteria.

{  
"query" : {  
"filtered" : {  
"query" : { "match\_all" : {} },  
"filter" : {  
"and" : [  
{ "or" : [  
{ "prefix" : { "name" : "Store" } },  
{ "prefix" : { "description" : "Store" } },  
{ "prefix" : { "floors.name" : "Store" } },  
{ "prefix" : { "floors.description" : "Store" } }  
]},  
{ "not": { "filter" : { "term" : { "security\_level" : 2 } } } },  
{ "not": { "filter" : { "term" : { "floors.security\_level" : 2 } } } }  
]  
}  
}  
}  
}

Can anyone please help me?

Thanks.  
Best regards,  
Hugo

---

<div class="post-metadata">

**Author:** ![kimchy](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/kimchy/32/44952_2.png) [@kimchy](https://discuss.elastic.co/u/kimchy)\
**Post date:** [March 6, 2012, 9:01pm UTC](https://discuss.elastic.co/t/filtering-sub-documents/6917/2 "2012-03-06T21:01:17Z")

</div>

You need to use nested mapping to treat inner array of objects as a "self sufficient" document, and then use nested filter / query. See more here: [Elasticsearch Platform — Find real-time answers at scale | Elastic](http://www.elasticsearch.org/guide/reference/mapping/nested-type.html).

Also, note you use things like prefix filter, and that part is not analyzed. So, if you index desc as "First Store", the terms created are "first" and "store" (by the default standard analyzer), which means using prefix filter (or query) with "First" will not match anything.

On Tuesday, March 6, 2012 at 7:59 PM, Hugo wrote:

> Hi all,
> 
> I have a document structure like this:
> 
> {  
> "\_index": "building",  
> "\_type": "info",  
> "\_source": {  
> "name": "First building",  
> "security\_level": 1,  
> "state": 1,  
> "description": "first area obs",  
> "floors": [  
> {  
> "description": "First Store",  
> "name": "First floor",  
> "security\_level": 2  
> },  
> {  
> "description": "Second Store",  
> "name": "Second floor",  
> "security\_level": 1  
> }  
> ]  
> }  
> }
> 
> and I want to search by floor name/description and/or building name/description but omitting the results if the user does not have the correct security level.  
> For instance if I try to find "First" and my security\_level is 0 I should not get any hit, but if my security level is 1 or 2 I should get one hit.  
> Also if I try to find "Store" and my security\_level is 0 I should not get any hit, but if my security level is 1 or 2 I should get one hit.
> 
> I've tried using the following query (for a user with security\_level equal to 1) but is does not work because it filters all documents that have one or more floors.security\_level equal to 2, even if there are other floors.security\_level with 0 or 1 that match the other criteria.
> 
> {  
> "query" : {  
> "filtered" : {  
> "query" : { "match\_all" : {} },  
> "filter" : {  
> "and" : [  
> { "or" : [  
> { "prefix" : { "name" : "Store" } },  
> { "prefix" : { "description" : "Store" } },  
> { "prefix" : { "floors.name ([http://floors.name](http://floors.name))" : "Store" } },  
> { "prefix" : { "floors.description" : "Store" } }  
> ]},  
> { "not": { "filter" : { "term" : { "security\_level" : 2 } } } },  
> { "not": { "filter" : { "term" : { "floors.security\_level" : 2 } } } }  
> ]  
> }  
> }  
> }  
> }
> 
> Can anyone please help me?
> 
> Thanks.  
> Best regards,  
> Hugo

---

<div class="post-metadata">

**Author:** ![Hugo](https://avatars.discourse-cdn.com/v4/letter/h/b38774/32.png) [@Hugo](https://discuss.elastic.co/u/Hugo)\
**Post date:** [March 7, 2012, 12:46pm UTC](https://discuss.elastic.co/t/filtering-sub-documents/6917/3 "2012-03-07T12:46:25Z")

</div>

Hi Shay,

Thanks for the help! I've changed to the nested mapping and now its working.

Best regards,  
Hugo

On Tuesday, March 6, 2012 9:01:17 PM UTC, kimchy wrote:

> You need to use nested mapping to treat inner array of objects as a "self  
> sufficient" document, and then use nested filter / query. See more here:  
> [Elasticsearch Platform — Find real-time answers at scale | Elastic](http://www.elasticsearch.org/guide/reference/mapping/nested-type.html).
> 
> Also, note you use things like prefix filter, and that part is not  
> analyzed. So, if you index desc as "First Store", the terms created are  
> "first" and "store" (by the default standard analyzer), which means using  
> prefix filter (or query) with "First" will not match anything.
> 
> On Tuesday, March 6, 2012 at 7:59 PM, Hugo wrote:
> 
> Hi all,
> 
> I have a document structure like this:
> 
> {  
> "\_index": "building",  
> "\_type": "info",  
> "\_source": {  
> "name": "First building",  
> "security\_level": 1,  
> "state": 1,  
> "description": "first area obs",  
> "floors": [  
> {  
> "description": "First Store",  
> "name": "First floor",  
> "security\_level": 2  
> },  
> {  
> "description": "Second Store",  
> "name": "Second floor",  
> "security\_level": 1  
> }  
> ]  
> }  
> }
> 
> and I want to search by floor name/description and/or building  
> name/description but omitting the results if the user does not have the  
> correct security level.  
> For instance if I try to find "First" and my security\_level is 0 I should  
> not get any hit, but if my security level is 1 or 2 I should get one hit.  
> Also if I try to find "Store" and my security\_level is 0 I should not get  
> any hit, but if my security level is 1 or 2 I should get one hit.
> 
> I've tried using the following query (for a user with security\_level equal  
> to 1) but is does not work because it filters all documents that have one  
> or more floors.security\_level equal to 2, even if there are other  
> floors.security\_level with 0 or 1 that match the other criteria.
> 
> {  
> "query" : {  
> "filtered" : {  
> "query" : { "match\_all" : {} },  
> "filter" : {  
> "and" : [  
> { "or" : [  
> { "prefix" : { "name" : "Store" } },  
> { "prefix" : { "description" : "Store" } },  
> { "prefix" : { "floors.name" : "Store" } },  
> { "prefix" : { "floors.description" : "Store" } }  
> ]},  
> { "not": { "filter" : { "term" : { "security\_level" : 2 } } } },  
> { "not": { "filter" : { "term" : { "floors.security\_level" : 2 } } } }  
> ]  
> }  
> }  
> }  
> }
> 
> Can anyone please help me?
> 
> Thanks.  
> Best regards,  
> Hugo

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [July 6, 2017, 3:36am UTC](https://discuss.elastic.co/t/filtering-sub-documents/6917/4 "2017-07-06T03:36:50Z")

</div>


