3

I'm using Aggregation to do a query and lookup. What's the most efficient way of returning both the results and count using one server call?

I've seen there is a way to do this using Facets, however, I'd like to do this using a Fluent expression with typed classes so I can abstract the logic into a generic extension method.

My current code looks something like this:

collection
  .Aggregate ()
  .Match (Builders<Order>.Filter...)
  .Lookup (...)
  .Project<Order> (Builders<Order>.Projection.Exclude ...)

2 Answers 2

3
+25

I believe you are looking for the $group operator.

collection
.Aggregate ()
.Match (Builders<Order>.Filter...)
.Lookup (...)
.Project<Order> (Builders<Order>.Projection.Exclude ...)
.Group(x => x.OrderId, g => new { ResultCount = g.Count(), Data = g.Select(x => new Order { SomeOrderProperty = x.AnotherOne}).ToList() }).FirstOrDefault();

This will give you an anonymous object containing your count and results in one. I dont know how your entity looks so I have assumed some names but you should be able to infer from this.

Sign up to request clarification or add additional context in comments.

1 Comment

Are you sure this is (still) correct? After applying, I only have 1 search result left.
0

The answer above will return the total count but only 1 search result which is not correct.

While browsing the source code of the C# driver v2.22 and the unit tests, I was able to construct the correct query to get both the limited search result to 20 and also get the total count of documents at the server for this search query.

            var result = await collection.Aggregate()
                        .Search(Builders<Product>.Search.Wildcard(g => g.Name, searchText),
                                indexName: "products",
                                count: new MongoDB.Driver.Search.SearchCountOptions { Type = MongoDB.Driver.Search.SearchCountType.Total })
                        .Project<Product>(Builders<Product>.Projection
                            .SearchMeta(x => x.MetaResult)
                                .Include(p => p.Name))
                        .Limit(1).SortBy(p => p.Name)
                                .ToListAsync(cancellationToken: cancellationToken);

this corresponds to the following Mongo pipeline expression:

[
  {
    $search: {
      wildcard: {
        query: "sunshine",
        path: "name",
      },
      count: { type: "total" },
      index: "products",
    },
  },
  {
    $project: {
      metaResult: "$$SEARCH_META",
      name: 1,
    },
  },
  { $limit: NumberLong(1) },
  { $sort: { name: 1 } },
]

You would need to add the SearchMetaResult.cs to the Product class so that the deserializer correctly maps the additional count meta data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.