O'Neil Tomlinson
O'Neil Tomlinson

Reputation: 888

Facet Atlas Search returning the $$SEARCH_META using C# MongoDB.Driver

I would like to do a Facet Search that returns the "$$SEARCH_META" based on the documentation (https://www.mongodb.com/docs/atlas/atlas-search/facet/). A snippet of the search definition from the documentation is like the below. Im interested in defining the "{"$replaceWith": "$$SEARCH_META"}"

{
    "$facet": {
      "docs": [
        { "$project":
          {
            "title": 1,
            "released": 1
          }
        }
      ],
      "meta": [
        {"$replaceWith": "$$SEARCH_META"},
        {"$limit": 1}
      ]
    }
  },

I have the following book Collection (Reduced for brevity)

[
    {
        "_id": "11111",
        "Published": true,
        "Description": "Description fo title 1",
        "Publisher": "BigBook Pub",
        "Title": "This is my first BigBook title",
        "Type": "fiction"
    }
]

My code (which ill show shortly) generates the following aggregation definition ($search, $project and $facet)

[
    {
        "$search": {
            "facet": {
                "operator": {
                    "compound": {
                        "should": [
                            {
                                "text": {
                                    "query": "Jon West",
                                    "path": [
                                        "Title",
                                        "Publisher",
                                        "Description"
                                    ]
                                }
                            }
                        ]
                    }
                },
                "facets": {
                    "publisherFacet": {
                        "type": "string",
                        "path": "Publisher"
                    },
                    "typeFacet": {
                        "type": "string",
                        "path": "Type"
                    }
                }
            },
            "index": "my-index"
        }
    },
    {
        "$project": {
            "_id": 1,
            "Publisher": 1,
            "Title": 1,
            "Description": 1
        }
    },
    {
        "$facet": {
            "docs": [
                {
                    "$project": {
                        "_id": 1,
                        "Publisher": 1,
                        "Title": 1,
                        "Description": 1
                    }
                }
            ]
        }
    }
]

From the above you can see that it is generating the $facet aggregation ($facet/docs/$project) which is similar to the definition in the atlas documentation, but im unable to work out how to generate section "$facet/meta/$replaceWith" as in the documentation

The Code that produced the above aggregation definition is as follows. It was simplfied for brevity. You will see a commented out bit where i was trying to generate the "{"$replaceWith": "$$SEARCH_META"}" but without successful. How do i generate this section?

public IEnumerable<Book> Search<T>(IMongoCollection<Book> collection)
        {
            var aggregateStage = collection.Aggregate();
    
            #region $search Aggregation Stage
                var compoundSearchDefinition = Builders<Book>.Search.Compound();
                compoundSearchDefinition.Should(Builders<Book>.Search.Text(listOfSearchableFields, 'Jon West'));
    
    
                var myFacets = new List<SearchFacet<Book>>
                {
                    Builders<Book>.SearchFacet.String("publisherFacet", "Publisher"),
                    Builders<Book>.SearchFacet.String("typeFacet", "Type")
                };
                var searchAndFacetDefinition = Builders<Book>.Search.Facet(compoundSearchDefinition, facets: myFacets);
    
    
                var textSearchResult = aggregateStage.Search(
                    searchAndFacetDefinition,
                    indexName: searchIndexSettings.Value.BookIndexName);
    
    
                var projectionDefinition = new ProjectionDefinitionBuilder<Book>()
                    .Include(clip => clip.Id)
                    .Include(clip => clip.Publisher)
                    .Include(clip => clip.Title)
                    .Include(clip => clip.Description);
    
                var searchAggregateStage = textSearchResult.Project<Book>(projectionDefinition);
            #endregion
    
    
    
    
            #region $facet Aggregation Stage
                PipelineDefinition<Book, Book> projectPipelineDef = new EmptyPipelineDefinition<Book>();
                PipelineDefinition<Book, Book> metaPipelineDef = new EmptyPipelineDefinition<Book>();
    
    
                ProjectionDefinition<Book, Book> projection1 = Builders<Book>.Projection
                    .Include(clip => clip.Id)
                    .Include(clip => clip.Publisher)
                    .Include(clip => clip.Title)
                    .Include(clip => clip.Description);
    
    
    
                var projDef = projectPipelineDef.Project(projection1);
                //  var metaDef = metaPipelineDef.ReplaceWith("$$SEARCH_META");
    
                var aggregateFacet1 = AggregateFacet.Create("docs", projDef);
                //var aggregateFacet2 = AggregateFacet.Create("meta", metaDef);
    
                var aggregateFacetList = new List<AggregateFacet<Book>>()
                {
                    aggregateFacet1,
                //    aggregateFacet2
                };
    
                
                var facetAggregateFluent = searchAggregateStage.Facet(aggregateFacetList);
            #endregion
    
    
            var result1 = facetAggregateFluent.ToList()[0].Facets[0].Output<Book>();
            return result1;
        }

And the Book Class

public class Book
{
    public bool Published { get; set; }
    public string Description { get; set; }
    public string Publisher { get; set; }
    public string Title { get; set; }
    public string Type { get; set; }
}

Upvotes: 0

Views: 189

Answers (1)

O&#39;Neil Tomlinson
O&#39;Neil Tomlinson

Reputation: 888

I manage to get it working by doing the following

So instead of

  //  var metaDef = metaPipelineDef.ReplaceWith("$$SEARCH_META");

I did this

var searchMetaPipelineDefinition = new EmptyPipelineDefinition<Book>()
    .AppendStage<Book, Book, Book>("{\"$replaceWith\":\"$$SEARCH_META\"}")
    .AppendStage<Book, Book, Metum>("{\"$limit\":1}");

With these additional classes to represent the Facet and metadata

public class Bucket
{
    public string _id { get; set; }
    public long count { get; set; }
}

public class TypeFacet
{
    public List<Bucket> buckets { get; set; }
}

public class Count
{
    public long lowerBound { get; set; }
}


public class Facet
{
    public TypeFacet clipTypeFacet { get; set; }
    public PublisherFacet publisherFacet { get; set; }
}

public class Metum
{
    public Count count { get; set; }
    public Facet facet { get; set; }
}

public class PublisherFacet
{
    public List<Bucket> buckets { get; set; }
}

Upvotes: 0

Related Questions