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!