2525import org .elasticsearch .common .bytes .BytesReference ;
2626import org .elasticsearch .common .compress .CompressedXContent ;
2727import org .elasticsearch .common .settings .Settings ;
28+ import org .elasticsearch .common .xcontent .XContentBuilder ;
2829import org .elasticsearch .common .xcontent .XContentFactory ;
2930import org .elasticsearch .common .xcontent .XContentType ;
3031import org .elasticsearch .index .IndexService ;
@@ -148,6 +149,92 @@ public void testDotsWithDynamicNestedMapper() throws Exception {
148149 e .getMessage ());
149150 }
150151
152+ public void testNestedHaveIdAndTypeFields () throws Exception {
153+ DocumentMapperParser mapperParser1 = createIndex ("index1" , Settings .builder ()
154+ .put ("index.mapping.single_type" , false ).build ()
155+ ).mapperService ().documentMapperParser ();
156+ DocumentMapperParser mapperParser2 = createIndex ("index2" , Settings .builder ()
157+ .put ("index.mapping.single_type" , true ).build ()
158+ ).mapperService ().documentMapperParser ();
159+
160+ XContentBuilder mapping = XContentFactory .jsonBuilder ().startObject ().startObject ("type" ).startObject ("properties" );
161+ {
162+ mapping .startObject ("foo" );
163+ mapping .field ("type" , "nested" );
164+ {
165+ mapping .startObject ("properties" );
166+ {
167+
168+ mapping .startObject ("bar" );
169+ mapping .field ("type" , "keyword" );
170+ mapping .endObject ();
171+ }
172+ mapping .endObject ();
173+ }
174+ mapping .endObject ();
175+ }
176+ {
177+ mapping .startObject ("baz" );
178+ mapping .field ("type" , "keyword" );
179+ mapping .endObject ();
180+ }
181+ mapping .endObject ().endObject ().endObject ();
182+ DocumentMapper mapper1 = mapperParser1 .parse ("type" , new CompressedXContent (mapping .string ()));
183+ DocumentMapper mapper2 = mapperParser2 .parse ("type" , new CompressedXContent (mapping .string ()));
184+
185+ XContentBuilder doc = XContentFactory .jsonBuilder ().startObject ();
186+ {
187+ doc .startArray ("foo" );
188+ {
189+ doc .startObject ();
190+ doc .field ("bar" , "value1" );
191+ doc .endObject ();
192+ }
193+ doc .endArray ();
194+ doc .field ("baz" , "value2" );
195+ }
196+ doc .endObject ();
197+
198+ // Verify in the case where multiple types are allowed that the _uid field is added to nested documents:
199+ ParsedDocument result = mapper1 .parse (SourceToParse .source ("index1" , "type" , "1" , doc .bytes (), XContentType .JSON ));
200+ assertEquals (2 , result .docs ().size ());
201+ // Nested document:
202+ assertNull (result .docs ().get (0 ).getField (IdFieldMapper .NAME ));
203+ assertNotNull (result .docs ().get (0 ).getField (UidFieldMapper .NAME ));
204+ assertEquals ("type#1" , result .docs ().get (0 ).getField (UidFieldMapper .NAME ).stringValue ());
205+ assertEquals (UidFieldMapper .Defaults .NESTED_FIELD_TYPE , result .docs ().get (0 ).getField (UidFieldMapper .NAME ).fieldType ());
206+ assertNotNull (result .docs ().get (0 ).getField (TypeFieldMapper .NAME ));
207+ assertEquals ("__foo" , result .docs ().get (0 ).getField (TypeFieldMapper .NAME ).stringValue ());
208+ assertEquals ("value1" , result .docs ().get (0 ).getField ("foo.bar" ).binaryValue ().utf8ToString ());
209+ // Root document:
210+ assertNull (result .docs ().get (1 ).getField (IdFieldMapper .NAME ));
211+ assertNotNull (result .docs ().get (1 ).getField (UidFieldMapper .NAME ));
212+ assertEquals ("type#1" , result .docs ().get (1 ).getField (UidFieldMapper .NAME ).stringValue ());
213+ assertEquals (UidFieldMapper .Defaults .FIELD_TYPE , result .docs ().get (1 ).getField (UidFieldMapper .NAME ).fieldType ());
214+ assertNotNull (result .docs ().get (1 ).getField (TypeFieldMapper .NAME ));
215+ assertEquals ("type" , result .docs ().get (1 ).getField (TypeFieldMapper .NAME ).stringValue ());
216+ assertEquals ("value2" , result .docs ().get (1 ).getField ("baz" ).binaryValue ().utf8ToString ());
217+
218+ // Verify in the case where only a single type is allowed that the _id field is added to nested documents:
219+ result = mapper2 .parse (SourceToParse .source ("index2" , "type" , "1" , doc .bytes (), XContentType .JSON ));
220+ assertEquals (2 , result .docs ().size ());
221+ // Nested document:
222+ assertNull (result .docs ().get (0 ).getField (UidFieldMapper .NAME ));
223+ assertNotNull (result .docs ().get (0 ).getField (IdFieldMapper .NAME ));
224+ assertEquals ("1" , result .docs ().get (0 ).getField (IdFieldMapper .NAME ).stringValue ());
225+ assertEquals (IdFieldMapper .Defaults .NESTED_FIELD_TYPE , result .docs ().get (0 ).getField (IdFieldMapper .NAME ).fieldType ());
226+ assertNotNull (result .docs ().get (0 ).getField (TypeFieldMapper .NAME ));
227+ assertEquals ("__foo" , result .docs ().get (0 ).getField (TypeFieldMapper .NAME ).stringValue ());
228+ assertEquals ("value1" , result .docs ().get (0 ).getField ("foo.bar" ).binaryValue ().utf8ToString ());
229+ // Root document:
230+ assertNull (result .docs ().get (1 ).getField (UidFieldMapper .NAME ));
231+ assertNotNull (result .docs ().get (1 ).getField (IdFieldMapper .NAME ));
232+ assertEquals ("1" , result .docs ().get (1 ).getField (IdFieldMapper .NAME ).stringValue ());
233+ assertEquals (IdFieldMapper .Defaults .FIELD_TYPE , result .docs ().get (1 ).getField (IdFieldMapper .NAME ).fieldType ());
234+ assertNull (result .docs ().get (1 ).getField (TypeFieldMapper .NAME ));
235+ assertEquals ("value2" , result .docs ().get (1 ).getField ("baz" ).binaryValue ().utf8ToString ());
236+ }
237+
151238 public void testPropagateDynamicWithExistingMapper () throws Exception {
152239 DocumentMapperParser mapperParser = createIndex ("test" ).mapperService ().documentMapperParser ();
153240 String mapping = XContentFactory .jsonBuilder ().startObject ().startObject ("type" )
@@ -639,7 +726,7 @@ public void testDynamicDottedFieldNameLongArrayWithExistingParentWrongType() thr
639726 .value (0 )
640727 .value (1 )
641728 .endArray ().endObject ().bytes ();
642- MapperParsingException exception = expectThrows (MapperParsingException .class ,
729+ MapperParsingException exception = expectThrows (MapperParsingException .class ,
643730 () -> mapper .parse (SourceToParse .source ("test" , "type" , "1" , bytes , XContentType .JSON )));
644731 assertEquals ("Could not dynamically add mapping for field [foo.bar.baz]. "
645732 + "Existing mapping for [foo] must be of type object but found [long]." , exception .getMessage ());
@@ -758,7 +845,7 @@ public void testDynamicDottedFieldNameLongWithExistingParentWrongType() throws E
758845 BytesReference bytes = XContentFactory .jsonBuilder ()
759846 .startObject ().field ("foo.bar.baz" , 0 )
760847 .endObject ().bytes ();
761- MapperParsingException exception = expectThrows (MapperParsingException .class ,
848+ MapperParsingException exception = expectThrows (MapperParsingException .class ,
762849 () -> mapper .parse (SourceToParse .source ("test" , "type" , "1" , bytes , XContentType .JSON )));
763850 assertEquals ("Could not dynamically add mapping for field [foo.bar.baz]. "
764851 + "Existing mapping for [foo] must be of type object but found [long]." , exception .getMessage ());
@@ -880,7 +967,7 @@ public void testDynamicDottedFieldNameObjectWithExistingParentWrongType() throws
880967
881968 BytesReference bytes = XContentFactory .jsonBuilder ().startObject ().startObject ("foo.bar.baz" ).field ("a" , 0 ).endObject ().endObject ()
882969 .bytes ();
883- MapperParsingException exception = expectThrows (MapperParsingException .class ,
970+ MapperParsingException exception = expectThrows (MapperParsingException .class ,
884971 () -> mapper .parse (SourceToParse .source ("test" , "type" , "1" , bytes , XContentType .JSON )));
885972
886973 assertEquals ("Could not dynamically add mapping for field [foo.bar.baz]. "
@@ -1017,7 +1104,7 @@ public void testNoLevel() throws Exception {
10171104 .field ("test2" , "value2" )
10181105 .startObject ("inner" ).field ("inner_field" , "inner_value" ).endObject ()
10191106 .endObject ()
1020- .bytes (),
1107+ .bytes (),
10211108 XContentType .JSON ));
10221109
10231110 assertThat (doc .rootDoc ().get ("test1" ), equalTo ("value1" ));
@@ -1036,7 +1123,7 @@ public void testTypeLevel() throws Exception {
10361123 .field ("test2" , "value2" )
10371124 .startObject ("inner" ).field ("inner_field" , "inner_value" ).endObject ()
10381125 .endObject ().endObject ()
1039- .bytes (),
1126+ .bytes (),
10401127 XContentType .JSON ));
10411128
10421129 assertThat (doc .rootDoc ().get ("type.test1" ), equalTo ("value1" ));
@@ -1056,7 +1143,7 @@ public void testNoLevelWithFieldTypeAsValue() throws Exception {
10561143 .field ("test2" , "value2" )
10571144 .startObject ("inner" ).field ("inner_field" , "inner_value" ).endObject ()
10581145 .endObject ()
1059- .bytes (),
1146+ .bytes (),
10601147 XContentType .JSON ));
10611148
10621149 assertThat (doc .rootDoc ().get ("type" ), equalTo ("value_type" ));
@@ -1077,7 +1164,7 @@ public void testTypeLevelWithFieldTypeAsValue() throws Exception {
10771164 .field ("test2" , "value2" )
10781165 .startObject ("inner" ).field ("inner_field" , "inner_value" ).endObject ()
10791166 .endObject ().endObject ()
1080- .bytes (),
1167+ .bytes (),
10811168 XContentType .JSON ));
10821169
10831170 assertThat (doc .rootDoc ().get ("type.type" ), equalTo ("value_type" ));
@@ -1098,7 +1185,7 @@ public void testNoLevelWithFieldTypeAsObject() throws Exception {
10981185 .field ("test2" , "value2" )
10991186 .startObject ("inner" ).field ("inner_field" , "inner_value" ).endObject ()
11001187 .endObject ()
1101- .bytes (),
1188+ .bytes (),
11021189 XContentType .JSON ));
11031190
11041191 // in this case, we analyze the type object as the actual document, and ignore the other same level fields
0 commit comments