[CSHARP-4666] Support projecting a single field with Find on servers prior to 4.4 Created: 05/Jun/23  Updated: 28/Oct/23  Resolved: 11/Jul/23

Status: Closed
Project: C# Driver
Component/s: None
Affects Version/s: None
Fix Version/s: 2.21.0

Type: New Feature Priority: Unknown
Reporter: Shawn Weaver Assignee: Robert Stam
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: Text File Program-1.cs    
Issue Links:
Duplicate
is duplicated by CSHARP-4727 IFindFluent.Project on a single field... Closed
Documentation Changes: Not Needed
Documentation Changes Summary:

1. What would you like to communicate to the user about this feature?
2. Would you like the user to see examples of the syntax and/or executable code and its output?
3. Which versions of the driver/connector does this apply to?


 Description   

Summary

Projection on document ID alone creates invalid projection.

C# Driver Version: 2.19.1, 2.19.2

MongoDB Version: 4.0, 4.2
MongoDB Topology: Using the Mongo driver for Azure; sharded cluster I think?

How to Reproduce

Attached is a small console application to demonstrate the error. I tested with both a string ID and an ObjectId ID, but both fail: strings are null, ObjectIDs are empty.

The projection is pretty simple, in the test case, it's just:

collection.Find(_ => true).Project(x => x.Id)

(Finding all documents just for the small test I have.)

However, the projection it generates in v2.19+ is:

find({ }, { "_v" : "$_id", "_id" : 0 })

In prior versions (we were using 2.14), this code worked, and the generated projection is what I'd have expected:

find({ }, { "_id" : 1 })



 Comments   
Comment by Githook User [ 11/Jul/23 ]

Author:

{'name': 'rstam', 'email': 'robert@robertstam.org', 'username': 'rstam'}

Message: CSHARP-4666: Support projecting a single field with Find on servers prior to 4.4.
Branch: master
https://github.com/mongodb/mongo-csharp-driver/commit/4aadc9f64decb55d24fefe72e0fbccf135d49de5

Comment by Robert Stam [ 11/Jul/23 ]

We have re-examined this issue with valuable insights provided by Oleksandr who encouraged us to consider supporting this particular use case in spite of the fact that we don't intend to support client-side projections in general.

Therefore I am re-opening this ticket.

Comment by Oleksandr Poliakov [ 03/Jul/23 ]

Hi, shawn.weaver@americanautoshield.com 
 
We have investigated this issue further and realized that even though we could improve driver to support this limited use-case, generally speaking the problem is not solvable with find operation projection and MongoDB server version before 4.4.
 
LINQ2 provider supported such projection simply because it was done client-side. It means if your code contains any calculation the LINQ2 provider will investigate what fields are involved in the calculation and grab all of them from the database, to let client code perform all necessary LINQ expressions in memory. Such approach works well in terms of support of different use-cases, but could lead to huge suboptimal database output (for example if you have an array property and you need to output the array size - in such cases whole array has to be pulled to client just for counting purposes). In LINQ3 provider we made a conscious decision to translate all LINQ statements to the server side aggregation expressions. In such approach no extra data would be pulled from the database. As the side-effect to have a proper server-side projection - the database has to support aggregation expressions. MongoDB 4.0 and 4.2 does not support aggregation expressions in Find projection. Such support was implemented in version 4.4.
 
So as a workarounds for your problem we can suggest one of the following:
1) Upgrade your MongoDB to the version 4.4 or above if it's possible.
2) Use Aggregate method instead of Find.

collection.Aggregate().Match(_ => true).Project(x => x.Id).ToList();

3) Configure MongoClient to use Linq2 provider, but keep in mind that LINQ2 provider eventually will be deprecated and removed.

var mongoClientSettings = MongoClientSettings.FromConnectionString("mongodb://my-mongo-server");
mongoClientSettings.LinqProvider = LinqProvider.V2;
var mongoClient = new MongoClient(mongoClientSettings);

I hope this helps.
 
Sincerely,
Oleksandr

 

Comment by Oleksandr Poliakov [ 12/Jun/23 ]

Hi shawn.weaver@americanautoshield.com, thank you for reporting the problem! We've reproduced the problem and can confirm that it affects all server versions before 4.4. We will prepare a fix for the problem. Meanwhile you can either update your code to the following snippet to make the client-side projection:

collection.Find(_ => true).Project(x => new { x.Id }).ToList().Select(x => x.Id)

or configure the mongo client to use Linq2 provider:

var mongoClientSettings = MongoClientSettings.FromConnectionString("mongodb://my-mongo-server");
mongoClientSettings.LinqProvider = LinqProvider.V2;
var mongoClient = new MongoClient(mongoClientSettings);

Comment by PM Bot [ 05/Jun/23 ]

Hi shawn.weaver@americanautoshield.com, thank you for reporting this issue! The team will look into it and get back to you soon.

Generated at Wed Feb 07 21:48:57 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.