M220N User Report

Can Someone figure out why my variable passed the the .Project() portion is not correct? I have double and triple checked it.

 List<ReportProjection> result = null;
               
                var filter = Builders<ReportProjection>.Projection
                    .Include("Count")
                    .Exclude("ID");

                result = await _commentsCollection
                  .WithReadConcern(ReadConcern.Majority)
                  .Aggregate()
                  .Group(new BsonDocument
                    {
                       { "_id", "$email" },
                       { "Count", new BsonDocument("$sum", 1)}
                    })
                  .Sort(new BsonDocument
                    {
                       {"count", -1 }
                    })
                  .Limit(20).Project<ReportProjection>(filter).ToListAsync();

                return new TopCommentsProjection(result);

You did not mentioned wat is the issue so we are not to sure what we need to look for. Syntax error, exception while running, bad result or no result at all. I am not familiar with .NET but two things jump into my eyes, ID vs _id in filter and count vs Count in sort.

I am sorry… My problem seems to be in the .Projection(filter) portion of the program.

There is a red line under the variable passed to the .Projection that states:

CS1503: Argument 1: Cannot convert from ‘MongoDB.Driver.ProjectionDefinition<M220N.Models.Projections.ReportProjection>’ to ‘MongoDB.Driver.ProjectionDefinition<MongoDB.BsonDocument, M220N.Models.Projections.ReportProjection>’

I do not know how to fix this.

Update… I got it to run, but the test fails… I get the following:

System.FormatException : Element 'Count" dies not match any field or property of class M220N.Models.projections.ReportProjection.

Any Ideas?

I believe I am missing a stage in this for the completion of the test. I don’t see a match stage. Is the intent of the Ticket for me to make the match stage and add it to the aggregation pipeline?

This is my latest code:

 public async Task<TopCommentsProjection> MostActiveCommentersAsync()
        {
            /**
                TODO Ticket: User Report
                Build a pipeline that returns the 20 most frequent commenters on the MFlix
                site. You can do this by counting the number of occurrences of a user's
                email in the `comments` collection.

                In addition, set the ReadConcern on the _commentsCollection to
                ensure the most accurate reads occur.
            */
            try
            {
                List<ReportProjection> result = null;
               
                var filter = Builders<BsonDocument>.Projection
                    .Include("Count")
                    .Exclude("_id");

               

                result = await _commentsCollection
                  .WithReadConcern(ReadConcern.Majority)
                  .Aggregate()
                  .Group(new BsonDocument
                    {
                       { "_id", "$Email" },
                       { "Count", new BsonDocument("$sum" , 1)}
                    })
                  .Sort(new BsonDocument
                    {
                       {"Count", -1 }
                    })
                  .Limit(20)
                  .Project<ReportProjection>(filter).ToListAsync();

I do not .NET but I am pretty sure the word match in this error message has nothing to do with a math stage. It looks like the class ReportProjection is missing a field named Count.

Thanks… Could I possibly be missing a $Match stage? I am unsure whether I can add it to the pipeline after .Aggregate, or if I am supposed to put the document filter inside the .Aggregate() method.

I wrote

I also see nothing in the TODO that says you need to match anything.

In your last version of the code you introduced another typing error you now have $Email rather than $email.

What is your take on:

I wrote

You changed all to Count but may be what you need is count since the error says Count is missing. May be the class ReportProjection uses count so you have to also use count in your code.

Thanks!!! I thought I was reading the directions right… LOL

In the class TopCommentsProjection class there is the following code.

public class ReportProjection
    {
        [BsonElement("_id")]
        public string Id { get; set; }

        public int Count { get; set; }
    }

I believe this to be what is being accessed in the .Project stage where I pass in the filter.

So… In the above class there is a get and set for Count… Wouldn’t this be what is being accessed?

So… If I break down this aggregation I am doing the following.

  1. Creating a filter that projects only the Count field
  2. Setting the ReadConcern to Majority
  3. Grouping the report on the email attribute in Collections class
  4. Creating a new field called “Count” and summing the email entries
  5. Sorting the return on the “Count” field in descending order
  6. Limiting my output to 20
  7. Passing the filter variable to the .Project
  8. Sending the results ToListAsync.

If I have the process right, then my question is where in this is the comment collection accessed and matched? Is it in the await _commentsCollection portion?

If the await allows access to the comments collection, then the email in the comments collection is not “email” it is “Email”… However when I use the “Email” my result doesn’t change.

Am I missing anything?

After really looking at the code… I believe my problem to be here:

.Group(new BsonDocument
                    {
                       { "_id", "$email" },
                       { "Count", new BsonDocument("$sum",  1) }
                    })

Specifically in the {“Count”, new BsonDocument("$sum", 1)}

While the sum statement is right in the aggregation pipeline, it looks like it is just a string here and not a call to sum the results of the query… Thoughts:?

Well… I don’t know why this worked, but the test now passes… I just changed all instances of Count to count. LOL Thanks for the help steeve!!! Your a lifesaver!!!

The only thing I can tell is that Count refers to a function so for fields you need to use the lower case count… Am I on the right track?