"Facet" fails to map "_id" field of a projection to "Id" of class (BUG?)

A “Projection” stage works fine when used directly and maps the “_id” field to “Id” property.

But when the same projection is used inside a facet, the driver fails to map “Id” property giving this error:

Unhandled exception. System.FormatException: Element ‘Id’ does not match any field or property of class TestModelDto.

I have checked the facet query inside a debug session. It seems pretty fine with a quirk: the projection query has “_id : 0” in it. could this be the reason?

Anyways, I have tried some variations on both the projection and the class itself.

  • it works only when we assign “Id” or “_id” of the previous stage to some name other than “Id”
    • an/or if we ignore assigning “Id” completely
  • doing so will result in null (or 0) assigned to “Id” property after the projection.

I have prepared minimal code here. It uses the new “top-level statements”, so please edit if your “dotnet” is an older version. uncomment data section to create a few test data.

  • comment out “Id” (and then “xId”) in the projection to make it run without the fail.
Click here to see test code
// See https://aka.ms/new-console-template for more information
using MongoDB.Bson;
using MongoDB.Driver;

var URI = "";

{
    MongoClient dbClient = new MongoClient(URI);

    var database = dbClient.GetDatabase("testme");
    var collection = database.GetCollection<BsonDocument>("facetbug");

    // create a few data
    // var data = new List<BsonDocument>(){
    //     new BsonDocument()    {        {"Name","Name 1"},{"Class","A"}    },
    //     new BsonDocument()    {        {"Name","Name 2"},{"Class","A"}    },
    //     new BsonDocument()    {        {"Name","Name 3"},{"Class","B"}    }
    //     };
    // collection.InsertMany(data);

    // read transactions
    var alldocs=collection.Find<BsonDocument>(_ => true).ToList().ToJson();
    Console.WriteLine($"All Documents:\n{ alldocs }\n");

    // read with projection
    var projection = PipelineStageDefinitionBuilder.Project<BsonDocument, TestModelDto>(x => new TestModelDto
    {
        Id = (ObjectId)x["_id"], // comment out this line for Facet to work, but becomes null afterward
        xId = (ObjectId)x["_id"],
        Name = (string)x["Name"],
    });
    var projected=collection.Aggregate().AppendStage(projection).ToList().ToJson();
    Console.WriteLine($"Projected Documents:\n{ projected }\n");

    // read with projection in facet
    var faceted = AggregateFacet.Create("single",
    PipelineDefinition<BsonDocument, TestModelDto>.Create(new IPipelineStageDefinition[]
        {
            projection
        }
    ));

    var facets = collection.Aggregate().Facet(faceted);
    var result = facets.Single().Facets.ToList().ToJson();
    Console.WriteLine($"Facet result:\n{ result }\n");
}

public class TestModelDto
{
    public ObjectId Id { get; init; }
    public ObjectId xId { get; init; }
    public string Name { get; init; }
}

we have a discussion here without a resolution for now: “Element ‘Id’ does not match any field or property of class” when using Project in Facet stage

Below are driver-generated queries and sample results

//Projection query as see in debug:
{ "$project" : {
   "Id" : "$_id", "xId" : "$_id", "Name" : "$Name", "_id" : 0
 } }

//Sample projected document
{ "_id" : ObjectId("637ea6b8f812644e17d5ac93"),
  "xId" : ObjectId("637ea6b8f812644e17d5ac93"),
  "Name" : "Name 1"
 }

//Facet query as seen in debug:
[{ "$facet" : { "single" : [{ "$project" : { 
    "Id" : "$_id", "xId" : "$_id", "Name" : "$Name", "_id" : 0 
    } }] }
}]

// Sample Facet result if Id property is ignored
{ "_t" : "AggregateFacetResult`1", "Name" : "single", "Output" : [
   { "_id" : ObjectId("000000000000000000000000"),
     "xId" : ObjectId("637ea6b8f812644e17d5ac93"),
     "Name" : "Name 1" }
] }
1 Like