[CSHARP-847] Linq provider needs to support non-constant boolean expressions Created: 21/Oct/13 Updated: 17/Apr/15 Resolved: 17/Apr/15 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | Linq |
| Affects Version/s: | 1.8.3 |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Major - P3 |
| Reporter: | Chris Waldron | Assignee: | Unassigned |
| Resolution: | Won't Fix | Votes: | 0 |
| Labels: | driver | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||||||
| Epic Link: | Rewrite Linq | ||||||||
| Description |
|
In the older Samus C# driver supported having non-constant boolean expression in the LINQ query. For example this is a valid expression in the Samus driver... //Get the first post having mismatched character count of its body length.... However in the official driver this is an invalid expression and throws an ArgumentException... //Get the first post having mismatched character count of its body length.... In his response, Craig G. Wilson indicates that the Samus driver is transforming the binary expression of a LINQ call into a MapReduce. It would seem that this is what the official driver should do as well. The official driver seems limiting and non-intuitive if it is going to allow LINQ queries. It clearly should support the complete complement of possible binary expressions not just a constant r-expression of a binary expression. Here's a link to the question on the mongo-charp forum ... |
| Comments |
| Comment by Craig Wilson [ 17/Apr/15 ] | ||||||||||||
|
We aren't going to fix this until the server updates the query language. | ||||||||||||
| Comment by Robert Stam [ 25/Oct/13 ] | ||||||||||||
|
Looking more closely at your example If you wanted to write this query against the current version of the server there are easier ways than using map/reduce or the aggregation framework. The simplest solution is to use a JavaScript where clause. For example, using the MongoDB shell:
You would write this in C# like this:
The MongoDB LINQ provider also lets you "inject" low level queries into a LINQ query, so you could also write this using LINQ like this:
Keep in mind that Javascript where clauses have more overhead than primitive queries, because 1. they can't use indexes and 2. they incur the overhead of translating each possible matching document to a Javascript document and executing the Javascript where clause. | ||||||||||||
| Comment by Chris Waldron [ 24/Oct/13 ] | ||||||||||||
|
Also I'm surprised that I'm the first to report this because I only encountered this issue because of your article on CodeProject using the Samus driver and trying to port your example to the official driver. Cheers, | ||||||||||||
| Comment by Chris Waldron [ 24/Oct/13 ] | ||||||||||||
|
Thanks Craig. This had a lot to do with silencing the critics. I'll use the aggregation example should the need arise. Cheers, | ||||||||||||
| Comment by Craig Wilson [ 24/Oct/13 ] | ||||||||||||
|
You're right. It might be a blocker for some people. However, the simple statement is that the Server does not support this yet. Until it does, it doesn't make sense for the driver to support it. We are most definitely not going to work around it using the agg framework or map/reduce because each of those alternatives (for this purpose) will provide a very sub-par experience with regards to performance. All I can ask you to do is vote for the Server ticket and wait. I guarantee that when that gets done, we'll be supporting it as well. That being said, regardless of the common-place of this particular requirement in SQL, you are the first to report this issue (probably not the first to encounter it). Additionally, in my experience of building apps using mongodb, I haven't needed this feature. In fact, a lot of devs have built a whole lot of applications without this particular feature. It's kind of a chicken-and-egg problem, asking if you can do something without knowing if you actually need it. Of course, if you do need it and didn't ask, then darn it. For now, we'll leave this ticket open and when the server team implements theirs, we'll implement this one. I hope that is satisfactory. | ||||||||||||
| Comment by Chris Waldron [ 24/Oct/13 ] | ||||||||||||
|
Craig, Being new to Mongo, I'm not familiar with all the possible workarounds. The aggregation example that you've demonstrated seems to be a reasonable alternative. My request is more about completeness of LINQ usage and familiarity coming from SQL. In order MongoDB adoption I have to response to critics who are looking for any excuse to put up resistance. I need to make sure that the LINQ driver can be used in a natural manner thus field comparison is going to be an issue. Whether the CSHARP driver generate MapReduce or the aggregation is not the underlying issue for me. That is a driver concern. What is my main concern is the completeness of LINQ binary comparison. Telling developers that they can't do something that is natural for them to do will be a huge roadblock for me to for MongoDB's adoption. Cheers, | ||||||||||||
| Comment by Craig Wilson [ 24/Oct/13 ] | ||||||||||||
|
As Robert linked, There is a way you can use the aggregation framework to do this and a future update of the driver will probably support it ( So:
In LINQ this might look like this...
Above, we are going to compare "field1" and "field2" for equality and store the result into the newly created "matches" field, and then run a predicate on that document. Not that this is going to be relatively inefficient because an index cannot be used on the "matches" field, and so it would be in your best interest to have prefiltered this before the $project so that this final $match is run on a small set of data. | ||||||||||||
| Comment by Chris Waldron [ 24/Oct/13 ] | ||||||||||||
|
Robert I have a question. Is the scenario of comparing fields one that is atypical of MongoDB users. Comparing fields is quite common is SQL. Is this a missing feature of MongoDB or is this By Design? Could the C# Driver support field comparison using MapReduce via the parsing of the boolean expression? It would appear that the parser could determine the type of boolean expression and based on the type of expression generate the property action. Thx, | ||||||||||||
| Comment by Robert Stam [ 22/Oct/13 ] | ||||||||||||
|
I would add that if the underlying MongoDB query language starts supporting comparing two fields against each other, at that point we would modify our LINQ provider to support this type of query. You can follow (and vote on) the corresponding server ticket: | ||||||||||||
| Comment by Robert Stam [ 21/Oct/13 ] | ||||||||||||
|
A LINQ query has to be translated at runtime into an equivalent MongoDB query. We only support LINQ queries that can be translated to equivalent MongoDB queries (and more particularly: to efficient MongoDB queries, which means no JavaScript where clauses). The primary reason that the driver restricts the r-exp to constants is that the underlying MongoDB query language only allows comparing fields to constants. It is common for LINQ providers to not support every possible LINQ query that could be written. LINQ queries that have no equivalent in the underlying query language (MongoDB in our case, SQL in the case of LINQ to SQL, etc...) result in a runtime exception. |