[CSHARP-4493] "An object representing an expression must have exactly one field" when querying by Linq query with .ToLower() Created: 25/Jan/23 Updated: 28/Oct/23 Resolved: 23/May/23 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | LINQ3 |
| Affects Version/s: | 2.18.0 |
| Fix Version/s: | 2.19.2 |
| Type: | Bug | Priority: | Unknown |
| Reporter: | Sorin Pochtar | Assignee: | Oleksandr Poliakov |
| Resolution: | Fixed | Votes: | 0 |
| Labels: | triage | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Backwards Compatibility: | Fully Compatible |
| Documentation Changes: | Not Needed |
| Documentation Changes Summary: | 1. What would you like to communicate to the user about this feature? |
| Description |
| Comments |
| Comment by Githook User [ 24/May/23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Author: {'name': 'Oleksandr Poliakov', 'email': '31327136+sanych-sun@users.noreply.github.com', 'username': 'sanych-sun'}Message: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Githook User [ 23/May/23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Author: {'name': 'Oleksandr Poliakov', 'email': '31327136+sanych-sun@users.noreply.github.com', 'username': 'sanych-sun'}Message: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by James Kovacs [ 15/Feb/23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thank you for the additional details. We have successfully reproduced the bug and it is subtle... Using ToLower() necessitates the use of $expr to call the server-side $toLower function. Since you have two clauses in your filter both using $expr, you end up with a filter that looks roughly like this:
where expr1 is your any emails clause and expr2 is your contains address clause. When you call filter & empty, we optimize the predicate flattening the $and. And this is the root cause of the problem. We flatten:
into
In many/most cases in MQL, {{ expr1, expr2 }} is equivalent to $and: [expr1, expr2], but $expr requires a single argument, which cannot be an array. Thus the server throws an error when we send it this incorrectly simplified MQL. Now why doesn't this happen when you don't filter & empty? Because we don't attempt to simplify the filter and send {{ {$expr: expr1}, {$expr: expr2} }} to the server. Why doesn't this happen when you omit ToLower()? Because we don't need to use $expr to call $toLower and we don't combine expressions in an invalid way. We will include a fix for this issue in an upcoming release. Please watch this ticket for further updates. Below is a repro of the issue:
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Sorin Pochtar [ 28/Jan/23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hi @James, Sorry, I have skipped one detail which I considered unimportant. Our framework is adding an empty filter under the hood (someAdditionalPredicate is my example), so the actual query will look like:
As you can see, I added
predicate, but it does not help. The same as previously, if I remove one of .ToLower() the query does not generate an exception.
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by James Kovacs [ 28/Jan/23 ] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Thank you for reaching out to us about this issue. We have been unsuccessful in reproducing the exception message that you encountered. Here is the self-contained repro code:
When running this repro against a customers collection containing documents without an Emails array, I ran into a similar though not identical issue:
I was able to resolve this by adding the condition c.Emails != null && to the beginning of the predicate. Please try the repro provided above and let us know if there is additional code or particular documents in your collection that is causing it to fail in your use case. Sincerely, |