[CSHARP-4265] Can't project only certain properties of an array using Fluent Find Created: 21/Jul/22  Updated: 25/Jul/22

Status: Backlog
Project: C# Driver
Component/s: Builders
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Flavio Cimolin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Cluster: Standalone

Edition: MongoDB 5.0.9 Community

Summary

Using the C# driver and LINQ Fluent Find, I'm not able to project only certain properties of an array.{}

How to reproduce

Let's say I have this data in my database:

{
  "_id": {
    "$oid": "62baf9a2851424fdb8c226f8"
  },
  "Name": "Team A",
  "TeamData": {
    "Players": [
      {
        "FirstName": "First Name A",
        "LastName": "Last Name A"
      },
      {
        "FirstName": "First Name B",
        "LastName": "Last Name B"
      }
    ]
  }
} 

Using LINQ Fluent Find, I can't select an object containing only "LastName". By using this code:

var result = coll.Find("{}")
   .Project(x => x.TeamData.Players.Select(c => c.LastName))
   .ToList() 

The generated request for this ends up being:

{
    "find": "coll",
    "filter": {},
    "projection": {
        "Players.LastName": 1,
        "TeamData.Players": 1,
        "_id": 0
    }
} 

...which selects all of "Players" properties.

Directly inputting the json works, but is not the desired way:

var result = coll.Find("{}")
   .Project("{ 'TeamData.Players.LastName': 1 }")
   .ToList(); 

Additional Background

This spawned a question here.



 Comments   
Comment by James Kovacs [ 25/Jul/22 ]

Hi, fhcimolin@gmail.com,

We have investigated this issue further and realize that the problem is in how Fluent Find performs projections. We recommend using LINQ (via AsQueryable) (with LINQ2 or LINQ3) or Aggregate (with LINQ3) as noted by dmitry.lukyanov@mongodb.com in his previous response. Given that there are two available workarounds, we do not plan to prioritize this issue in the near term. If this will cause an issue, please comment on this ticket and we will reconsider.

Sincerely,
James

Comment by Dmitry Lukyanov (Inactive) [ 21/Jul/22 ]

Hey fhcimolin@gmail.com, thanks for your report, we will look at this and come back to you.
Meanwhile, you can use this workaround with LINQ or aggregate:

// works with LINQ2 and LINQ3
var result = coll.AsQueryable().Select(x => x.TeamData.Players.Select(c => c.LastName)).ToList();
 
// works only with LINQ3
var client = new MongoClient(new MongoClientSettings { LinqProvider = Linq.LinqProvider.V3 });
var db = client.GetDatabase("db");
var coll = db.GetCollection<TeamDto>("coll");
var result = coll.Aggregate().Project(x => x.TeamData.Players.Select(c => c.LastName)).ToList();

Comment by James Kovacs [ 21/Jul/22 ]

Self-contained repro:

using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
 
var settings = new MongoClientSettings { LinqProvider = LinqProvider.V3 };
var client = new MongoClient(settings);
var db = client.GetDatabase("test");
var coll = db.GetCollection<Team>("teams");
 
var query = coll.Find("{}").Project(x => x.TeamData.Players.Select(p => p.LastName));
Console.WriteLine(query);
 
record Team(ObjectId Id, string Name, TeamData TeamData);
record TeamData(IEnumerable<Player> Players);
record Player(string FirstName, string LastName);

Both LINQ2 and LINQ3 generate the following incorrect MQL:

find({ }, { "Players.LastName" : 1, "TeamData.Players" : 1, "_id" : 0 })

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