Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-3097

How to cleanly deal with full text search and sort by score when search term is an empty string?

    XMLWordPrintableJSON

Details

    • Icon: New Feature New Feature
    • Resolution: Done
    • Icon: Major - P3 Major - P3
    • None
    • None
    • None
    • None

    Description

      Hello,

       

      We are implementing full text search in our application and ran into a couple of situations that seemed less than ideal. Mainly when dealing with the possibility of the user entering in an empty string for the search string and trying to sort by score.

       

      1. Aggregation pipeline is unable to be built dynamically

      I was hoping i could do something like this to dynamically compose the pipeline.

       

       

      var query = GetCollection<TDocument>()
      .Aggregate()
      .Match(filter)
      .Skip(criteria.Skip)
      .Limit(criteria.Take);
       
      if (!String.IsNullOrWhiteSpace(criteria.SearchString))
      {
                      results = query
      .Sort(Builders<TDocument>.Sort.MetaTextScore("Score"));
      }
       
      query.Project(new {
      // stuff here
      }).ToList();
      
      

      What i noticed is that the sort filter was not getting added as a pipeline stage.

       

       

      2. There is no concept of an Empty Sort Definition like Filters so i couldn't sort by score which is ideal

       

       

      var filterDefinition = Builders<TDocument>.Filter.Empty
      if (!String.IsNullOrWhiteSpace(searchCriteria.SearchString))
      {                filterDefinition &= Builders<MediaDocument>.Filter.Text(searchCriteria.SearchString);            }
       
      var sortDefinition = Builders<TDocument>.Sort.Empty // <-- this doesn't exist like filters
       
      if (!String.IsNullOrWhiteSpace(criteria.SearchString))
      {
         sortDefinition &= Builders<TDocument>.Sort.MetaTextScore("Score")
      }
       
      var query = GetCollection<TDocument>()
      .Aggregate()
      .Match(filterDefinition)
      .Skip(criteria.Skip)
      .Limit(criteria.Take)
      .Sort(sortDefinition)
      query.Project(new { // stuff here }).ToList();;
      

       

       

      In the end i pretty much ended up doing this.  It works and does make sense but at the downside of duplicating parts of the query.

       

       

       if (!String.IsNullOrWhiteSpace(criteria.SearchString))
                  {
                      results = GetCollection<TDocument>()
                          .Aggregate()
                          .Match(filter)
                          .Skip(criteria.Skip)
                          .Limit(criteria.Take)
                          .Sort(Builders<TDocument>.Sort.MetaTextScore("Score"))
                          .ToList();
                  }
                  else
                  {
                      results = GetCollection<TDocument>()
                          .Aggregate()
                          .Match(filter)
                          .Skip(criteria.Skip)
                          .Limit(criteria.Take)
                          .ToList();
                  }
      

       

       

      I would love some feedback if there is a cleaner alternative way of doing the above.

       

      Thanks!

       

      Attachments

        Activity

          People

            Unassigned Unassigned
            michael_fyffe@homedepot.com Michael Fyffe
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: