BLQL filters and sorts cannot reach a nested field, though a dynamic index can be built on one
Maintainers usually reply within 2 days
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 57/100
Research direction
Start with src/BLite.Core/Query/Blql/BlqlFilter.cs and BlqlSort.cs, where BLQL reads fields, then compare those lookups with DynamicCollection.TryGetNestedValue in src/BLite.Core/DynamicCollection.cs. Use the oracle cases in tests/BLite.Tests/Oracles/DynamicDifferentialTests.cs and the repro here to check filters and sorting both with and without an index. Done means dotted paths return consistent, expected results across those cases.
Written by the indexing model from the issue text.
Description
On a DynamicCollection, a BLQL filter or sort on a dotted path ("meta.kind") treats the field as missing: $eq, $gt, $in match nothing, $ne and $nin match every document, and the in-memory sort keeps the scan order. CreateIndexAsync("meta.kind") and QueryIndexAsync on the same path work, and with that index BLQL scans it and then drops every document in its residual filter.
Found by the DynamicCollection oracle tests (tests/BLite.Tests/Oracles/DynamicDifferentialTests.cs, #272), which carry the affected rows (48: indexed/blql and plain/blql against LINQ-to-Objects and the typed collection, e.g. kind == Blue, kind in list, orderby kind) as a known candidate until this is fixed.
Repro
var col = engine.GetOrCreateCollection("p"); // and once more after: await col.CreateIndexAsync("meta.kind");
foreach (var (n, k) in new[] { ("a", 2), ("b", 0), ("c", 2) })
await col.InsertAsync(col.CreateDocument(["n", "meta", "kind"],
b => b.AddString("n", n).AddDocument("meta", m => m.AddInt32("kind", k))));
col.Query(BlqlFilter.Eq("meta.kind", 2)).ToList(); // expected [a, c], actual [] (indexed: [])
col.Query("{\"meta.kind\": 2}").ToList(); // expected [a, c], actual []
col.Query(BlqlFilter.Ne("meta.kind", 2)).ToList(); // expected [b], actual [a, b, c]
col.Query().OrderBy("meta.kind").ToList(); // expected [b, a, c], actual [a, b, c] (indexed: [b, c, a])
await col.QueryIndexAsync("idx_meta.kind", 2, 2).ToListAsync(); // [c, a], correct
Expected: a dotted path names the nested field in BLQL as it does for indexes: "dot-notation strings ("address.city") for schema-less collections" (README.md:65) and "Nested path index (dot-notation) — indexes a field inside an embedded document" (README.md:861). BLQL is "MQL-inspired" (README.md:97), and in MQL {"meta.kind": 2} is a path. The README's BLQL section (README.md:991-1130) does not say either way.
Actual: see above. With the index the filter is worse than useless: the scan finds the right documents and the residual filter removes them all. Only the index-served sort is right.
Mechanism (verified on 0450b97)
- Every BLQL operator reads its field with
BsonDocument.TryGetValue(CompareFilter.Matches,src/BLite.Core/Query/Blql/BlqlFilter.cs:315;InFilter,:408; the same for$exists,$type,$regex, the string and the array operators), and so doesBlqlSort.ToComparison(src/BLite.Core/Query/Blql/BlqlSort.cs:53-54). BsonDocument.TryGetValue(src/BLite.Bson/BsonDocument.cs:230) looks up a top-level name only. The dotted path is resolved only byDynamicCollection.TryGetNestedValue(src/BLite.Core/DynamicCollection.cs:2759), which the index paths use.BlqlQuery.GetScanSource(BlqlQuery.cs:302) finds the nested index throughFindBTreeIndexForField(DynamicCollection.cs:1091), which is why the single-key sort fast path (BlqlQuery.cs:241-258) orders by it correctly while the filter does not match.
Affected versions: BLQL has read fields this way since it was added (a86d458, 2026-02-24, v1.9.0). Reproduced on v5.2.3 / 0450b97.
Fix considerations
- One path lookup for BLQL (
TryGetNestedValuemade shared, or aBsonDocument.TryGetPath) used by every filter and byBlqlSort. MQL forbids dots in field names, so a dotted name can always mean a path; whether BLQL should follow that is your call, but the indexed and unindexed answers should agree either way. BlqlProjectiontakes field names too; whetherInclude("meta.kind")should project the nested field was not checked.
Related: #254 (open, BLQL's index-served sort and range scan, same GetScanSource), and the other BLQL rows of the same tests: #265, #266, #267, #268.
- Dominant language
- C#
- Stars
- 66
- Forks
- 6
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 58
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from EntglDb/BLite
-
GdprMode.Strict warns that deleted documents are not zeroed, but every delete zero-fills themPossibly taken @CaffeinatedCoder claimed this 1 day ago. Openbug gdpr package/core severity/low
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
EntglDb/BLite#299 · 1 comment ·
Maintainers usually reply within 2 days
-
bug package/core severity/medium triage
Difficulty 4/5 3-5 days Newbie friendliness 54/100
Maintainers usually reply within 2 days
-
bug package/core severity/medium
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#322 · 1 comment ·
Maintainers usually reply within 2 days
-
enhancement package/core
Difficulty 4/5 3-5 days Newbie friendliness 48/100
EntglDb/BLite#320 · 1 comment ·
Maintainers usually reply within 2 days
-
BLiteSession.Rollback() does not await the rollback: it returns while the transaction is still active, and failures go unobservedPossibly taken @CaffeinatedCoder claimed this 1 day ago. Openbug package/core severity/medium
Difficulty 3/5 1-2 days Newbie friendliness 78/100
EntglDb/BLite#307 · 1 comment ·
Maintainers usually reply within 2 days
Similar issues
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
swisstopo/swissgeol-boreholes-suite#3086 ·
Maintainers usually reply within 1 day
-
byte类型在条件中的解析BUGOpen
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
dotnetcore/FreeSql#2290 ·
-
status:waiting-for-triage type:bug
Difficulty 1/5 Under an hour Newbie friendliness 84/100
microsoftgraph/msgraph-sdk-dotnet#3194 ·
Maintainers usually reply within 1 day
-
Backend enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
Maintainers usually reply within 1 day
-
UI: money shows the minus sign next to the number, not before the currency (IL -3.0m, not -IL 3.0m)Openarea: sim area: unity enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
eyalgolan/statecraft-israel#1107 · 1 comment ·
Maintainers usually reply within 1 day