3

I have a new query for a collection that is already pulling and storing data for a configured type and I haven't come across that one before:

The serializer for field 'BookingRequests' must implement IBsonArraySerializer and provide item serialization info.

The object I have has the following structure:

public class DayBookings : IHasId
{
    public DayBookings()
    {
        BookingRequests = new Dictionary<string, TimestampedRequest<BookingRequest>>();
    }
    public DayBookings(TimestampedRequest<BookingRequest> bookingRequest, string restaurant) : this()
    {
        Id = $"{restaurant}_{bookingRequest.Request.Date.ToString("ddMMyyyy")}";

        Restaurant = restaurant;

        Date = bookingRequest.Request.Date;

        BookingRequests[bookingRequest.RequestId] = bookingRequest;
    }
    public string Id { get; set; }
    public string Restaurant { get; set; }
    public DateTime Date { get; set; }
    public Dictionary<string, TimestampedRequest<BookingRequest>> BookingRequests { get; set; }
}

where TimestampedRequest is a standard POCO object with generic data inside.

The configuration for that collection I run on start up is:

if (!BsonClassMap.IsClassMapRegistered(typeof(DayBookings)))
{
    BsonClassMap.RegisterClassMap<DayBookings>(cm =>
    {
        cm.AutoMap();

        cm.SetIdMember(cm.GetMemberMap(c => c.Id));

        var customDictionarySerializer = new DictionaryInterfaceImplementerSerializer<Dictionary<string, TimestampedRequest<BookingRequest>>>(dictionaryRepresentation: DictionaryRepresentation.Document,
                                                                                                                                                          keySerializer: new StringSerializer(BsonType.String),
                                                                                                                                                          valueSerializer: BsonSerializer.SerializerRegistry.GetSerializer<TimestampedRequest<BookingRequest>>());
      cm.GetMemberMap(c => c.BookingRequests)
        .SetSerializer(customDictionarySerializer);
   });

}

I added the custom serializer for that field in case I needed it but it has had no effect.

The query I'm trying to perform is this:

public async Task<IEnumerable<DateTime>> GetAllDatesWithUnconfirmedBookings(string restaurant)
        {
            IEnumerable<DateTime> dates = null;

            try
            {
                dates = await Collection.Find(Builders<DayBookings>.Filter.And(
                                                Builders<DayBookings>.Filter.Eq(d => d.Restaurant, restaurant),
                                                Builders<DayBookings>.Filter.Gte(d => d.Date, DateTime.UtcNow.Date),
                                                Builders<DayBookings>.Filter.ElemMatch(d => d.BookingRequests, b => b.Value.Request.Status == Domain.Requests.BookingStatus.Unconfirmed)))
                                        .SortBy(d => d.Date)
                                        .Project(d => d.Date)
                                        .ToListAsync();
            }
            catch (Exception ex)
            {
                Logger.Error(ex, $"Error getting all dates with pending bookings for Restaurant={restaurant}");
            }

            return dates;
        }

I couldn't find much information about the configuration I would have to set for the BookingRequests field so I would appreciate some help here.

Many thanks!

UPDATE

I ended up changing the way of querying the DB and did not have to set up the serializer configuration. Suppressing ElemMatch and performing forEachAsync solved my problem:

public async Task<IEnumerable<DateTime>> GetAllDatesWithUnconfirmedBookingsAsync(string restaurant)
    {
        var dates = new List<DateTime>();

        try
        {
            await Collection.Find(Builders<DayBookings>.Filter.And(
                                    Builders<DayBookings>.Filter.Eq(d => d.Restaurant, restaurant),
                                    Builders<DayBookings>.Filter.Gte(d => d.Date, DateTime.UtcNow.Date)))
                            .SortBy(d => d.Date)
                            .ForEachAsync(d =>
                            {
                                if (d.BookingRequests.Values.Any(b => b.Request.Status == Domain.Requests.BookingStatus.Unconfirmed))
                                {
                                    dates.Add(d.Date);
                                }
                            });
        }
        catch (Exception ex)
        {
            Logger.Error(ex, $"Error getting all dates with pending bookings for Restaurant={restaurant}");
        }

        return dates;
    }

UPDATE: THIS MIGHT WORK

I have come across another Dictionary serialization problem with another problem and after looking for a while I found this answer: https://stackoverflow.com/a/57990191/5293466 which has helped me getting the serialization issue go away. In fact, I got another query - not an ElemMatch but a PullFilter - working nicely against a Dictionary<string, CustomType>. I hope this helps people as it did it to me!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Carlos Torrecillas
  • 4,965
  • 7
  • 38
  • 69

0 Answers0