Как запросить коллекцию MongoDb с помощью драйвера C #, используя значения словаря в качестве параметров фильтра - PullRequest
3 голосов
/ 22 апреля 2019

У меня есть список событий

Где событие

public class Event
    {
        public int Id { get; set; }
        public int Seq { get; set; }

        public Event(int id, int seq)
        {
            Id = id;
            Seq = seq;
        }
    }

Я хочу сделать запрос в этом списке и получать только события с, скажем, значениями идентификаторов 1 и 2.

Тогда получите только те записи Event с Id 1, у которых Seq равен или больше 3

И получить только те записи Event с Id 2, у которых Seq равен или больше 4

В примере LINQ я создал словарь "eventsToRetrieve" для int, int со значениями, которые я хочу получить, как описано выше

[1,3]
[2,4]

Пример кода с C # / LINQ будет выглядеть так

 var allEvents = new List<Event>()
            {
                new Event(1, 1),
                new Event(1, 2),
                new Event(1, 3),
                new Event(1, 4),
                new Event(1, 5),
                new Event(2, 1),
                new Event(2, 2),
                new Event(2, 3),
                new Event(2, 4),
                new Event(2, 5),
                new Event(2, 6),
                new Event(3, 1),
                new Event(3, 2),
                new Event(3, 3),
            };

            var eventsToRetrieve = new Dictionary<int, int>()
            {
                { 1 ,3},
                { 2 ,4}
            };


            var eventsIWant = allEvents
           .Where(ev => eventsToRetrieve.Keys.Contains(ev.Id) 
               && ev.Seq >= eventsToRetrieve.Single(er => er.Key == ev.Id).Value 
           ).ToList();

Этот LINQ работает нормально, и я получаю ожидаемые результаты. Результатом «eventsIWant» являются только события со значениями

(1,3)
(1,4)
(1,5)
(2,4)
(2,5)
(2,6)

Теперь я хочу применить нечто похожее к коллекции mongoDb , которая выглядит как список выше. У меня есть коллекция eventsCollection с составным ключом (Id), который является уникальной комбинацией пар (EntityId, SequenceNumber).

Класс события


    public class Event
    {
        /// <summary>
        /// The composite key for this Event
        /// </summary>
        [BsonId]
        public EventId Id { get; internal set; }
    }

    public class EventId
    {
        public Guid EntityId { get; private set; }
        public long SequenceNumber { get; private set; }
    }

Я пробовал что-то вроде


var eventsIWant = await _eventsCollection.FindAsync( event => eventsToRetrieve.Keys.Contains(event.Id.EntityId)
&& event.Id.SequenceNumber >= eventsToRetrieve[event.Id.EntityId])

Но я получаю

System.ArgumentException: Unsupported filter MONGODB C#...

для

events.Id.SequenceNumber >= sitesWithLatestSequence[events.Id.EntityId])

часть.

Я также пробовал что-то похожее с инфраструктурой агрегации C # / MongoDB, но не смог заставить что-то работать

Есть ли способ сделать что-то похожее на то, что сделал LINQ, но в качестве монго-фильтра MongoDB или агрегации?

Извините, если название не очень точное, но не может придумать что-то лучшее. Открыт для предложений.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Примерно так (не смог проверить, но, надеюсь, это достаточно близко):

    var eventsToRetrieve = new Dictionary<Guid, long>()
    {
        { Guid.NewGuid() ,3},
        { Guid.NewGuid() ,4}
    };

    var parameterExpression = Expression.Parameter(typeof(Event));
    Expression idExpression = Expression.Property(parameterExpression, nameof(Event.Id));

    var body = 
        eventsToRetrieve.Aggregate(null, (Expression expression, KeyValuePair<Guid,long> etr) => 

        {
            var addedExpression =        
                                Expression.AndAlso(
                                Expression.Equal(Expression.Property(idExpression, nameof(EventId.EntityId)), Expression.Constant(etr.Key)),
                                Expression.LessThanOrEqual(Expression.Property(idExpression, nameof(EventId.SequenceNumber)), Expression.Constant(etr.Value)));
            return expression != null ? Expression.OrElse(expression,addedExpression) : addedExpression;
        });


    var filter = (Expression<Func<Event,bool>>) Expression.Lambda(body, parameterExpression);
0 голосов
/ 22 апреля 2019

Попробуйте следующее:

            var allEvents = new List<Event>()
            {
                new Event(1, 1),
                new Event(1, 2),
                new Event(1, 3),
                new Event(1, 4),
                new Event(1, 5),
                new Event(2, 1),
                new Event(2, 2),
                new Event(2, 3),
                new Event(2, 4),
                new Event(2, 5),
                new Event(2, 6),
                new Event(3, 1),
                new Event(3, 2),
                new Event(3, 3),
            };

            Dictionary<int, List<int>> dict = allEvents
                .GroupBy(x => x.Id, y => y.Seq)
                .ToDictionary(x => x.Key, y => y.ToList());

            Dictionary<int, List<int>> results = dict.Where(x => x.Value.Any(y => y >= 4))
                .GroupBy(x => x.Key, y => y.Value)
                .ToDictionary(x => x.Key, y => y.Where(z => z.Any(a => a >= 4)).SelectMany(a => a.Where(b => b >= 4)).ToList());

        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...