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" }
] }