MongoDB Projection with VectorSearch

43 Views Asked by At

I am trying to perform a vector search on a collection and map the results into a custom object that contains only some of the properties in the collection along with the vector score. I have managed to do this with the below code but it feels untidy and I am wondering if this can all be done as a projection. It also doesn't allow me to map properties from the collection class into the custom object unless their names match.

Here is my example:

I have a collection for my Accommodation class which contains the vector. I need to do a vector search and then map the results into a list of AccommodationRecommendation.

The classes:

class Accommodation
{
     Guid Id { get; set; }
     string Name { get; set; }
     string Description { get; set; }
     string double[] { get; set; }
     List<AccommodationImage> AccommodationImages { get; set; }
}

class AccommodationImage
{
     string Url{ get; set; }
}

class AccommodationRecommendation
{
     HotelSlim Hotel { get; set; }
     double Score { get; set; }
}

class AccommodationLite
{
     Guid Id { get; set; }
     string Name { get; set; }
     string ImagerUrl { get; set; }
}

This is my work so far. Note how i have to retrieve all of the images and then filter down to just one.

private async Task<List<AccommodationRecommendation>> VectorSearchInternal(
    System.Linq.Expressions.Expression<Func<Accommodation, object?>> field, 
    double[] baseVector, 
    int count, 
    string indexName)
{
    var output = new List<AccommodationRecommendation>();

    var options = new VectorSearchOptions<Accommodation>()
    {
        IndexName = indexName,
        NumberOfCandidates = 10000
    };

    var projectionDefinition = Builders<Accommodation>.Projection
             .Include(a => a.Id)
             .Include(a => a.Name)
             .Include(a => a.AccommodationImages)
             .Meta("score", "vectorSearchScore");

    var results = await Collection.Aggregate()
           .VectorSearch(field, baseVector, count + 1, options)
           .Project(projectionDefinition)
           .ToListAsync<BsonDocument>();

    foreach (var result in results)
    {
        var accom = BsonSerializer.Deserialize<AccommodationLite>(result);
        var images = result["AccommodationImages"].AsBsonArray;
        if (images != null && images.Any())
        {
            var image = BsonSerializer.Deserialize<Image>(images[0].AsBsonDocument);
            accom.ImageUrl = image.Url;
        }
        output.Add(new AccommodationRecommendation
        {
            RecommendedAccommodation = accom,
            Score = result["score"].AsDouble * 100
        });
    }
    return output;
}
0

There are 0 best solutions below