Skip to content

Commit 4389f8d

Browse files
anidotnetclaude
andcommitted
Fix embedded-field lookup into plain map values (#1335)
Nested-field filters such as address.city never matched when the nested object was a plain map instead of a document. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 58b7844 commit 4389f8d

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
- **Spatial indexes now work after reopening an MVStore file** ([#1334](https://github.com/nitrite/nitrite-java/pull/1334))
1717
- H2 reads persisted R-tree keys back as its own `Spatial` implementation, so queries, updates and removals on a reopened spatial index failed with a `ClassCastException` from `DefaultSpatial` to `MVSpatialKey`. Cursors and bounds comparisons now accept any `Spatial`. The on-disk format and public method signatures are unchanged.
1818
- Thanks to [@sfkamath](https://github.com/sfkamath) for the report and the fix.
19+
- **Filters on nested fields now match documents built from plain maps** ([#1335](https://github.com/nitrite/nitrite-java/issues/1335))
20+
- `Document.createDocument(Map)` keeps nested objects as plain `Map`s (as deserialized JSON does), but embedded-field lookup only descended into `Document` values. So `get("address.city")` returned `null` and `where("address.city").eq(...)` never matched. Lookup now descends into any `Map` value.
1921

2022
## Release 5.4.1 - Oct 17, 2026
2123

‎nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,17 @@ private Object recursiveGet(Object object, String[] remainingPath) {
561561
Arrays.copyOfRange(remainingPath, 1, remainingPath.length));
562562
}
563563

564+
if (object instanceof Map) {
565+
// a plain map (e.g. a document created from a deserialized map) is scanned like a document
566+
String key = remainingPath[0];
567+
if (isNullOrEmpty(key)) {
568+
throw new ValidationException("Invalid key provided");
569+
}
570+
571+
return recursiveGet(((Map<?, ?>) object).get(key),
572+
Arrays.copyOfRange(remainingPath, 1, remainingPath.length));
573+
}
574+
564575
if (object.getClass().isArray()) {
565576
// if the current level value is an array
566577

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) 2017-2021 Nitrite author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package org.dizitart.no2.integration.collection;
19+
20+
import org.dizitart.no2.Nitrite;
21+
import org.dizitart.no2.collection.Document;
22+
import org.dizitart.no2.collection.NitriteCollection;
23+
import org.junit.After;
24+
import org.junit.Before;
25+
import org.junit.Test;
26+
27+
import java.util.HashMap;
28+
import java.util.Map;
29+
30+
import static org.dizitart.no2.filters.FluentFilter.where;
31+
import static org.junit.Assert.assertEquals;
32+
33+
/**
34+
* Regression test for <a href="https://github.com/nitrite/nitrite-java/issues/1335">Issue 1335</a>.
35+
* <p>
36+
* A document built from a plain {@link Map} (e.g. deserialized JSON) keeps nested
37+
* objects as {@link Map}s instead of {@link Document}s. Embedded field access such as
38+
* {@code address.city} did not descend into those maps, so filters on nested fields
39+
* never matched.
40+
*
41+
* @author Anindya Chatterjee
42+
*/
43+
public class Issue1335Test {
44+
private Nitrite db;
45+
private NitriteCollection collection;
46+
47+
@Before
48+
public void setUp() {
49+
db = Nitrite.builder().openOrCreate();
50+
collection = db.getCollection("issue1335");
51+
52+
Map<String, Object> address = new HashMap<>();
53+
address.put("city", "bangalore");
54+
Map<String, Object> person = new HashMap<>();
55+
person.put("name", "amit");
56+
person.put("address", address);
57+
collection.insert(Document.createDocument(person));
58+
}
59+
60+
@After
61+
public void tearDown() {
62+
db.close();
63+
}
64+
65+
@Test
66+
public void testNestedMapField() {
67+
assertEquals(1, collection.find(where("name").eq("amit")).size());
68+
assertEquals(1, collection.find(where("address.city").eq("bangalore")).size());
69+
assertEquals(0, collection.find(where("address.city").notEq("bangalore")).size());
70+
}
71+
}

0 commit comments

Comments
 (0)