Как сделать коректно Subquery используя Realm

144
20 июня 2019, 18:20

UPD: прошу прощения за дезинформацию, знаний LINQ недостаточно что бы сделать коректный запрос через реалм. Я это немного поздно понял.

Допустим я имею 2 таблицы: HistoryItem и Quest

HistoryItem внутри имеет поле Quest и другие данные. В таблице Quest есть поле MaxRepeats.

Что мне нужно получить: мне нужно получить список квестов, который отфильтрован по дате + отфильтрован по количеству записей ЭТОГО ЖЕ КВЕСТА внутри HistoryItem.

В даном случае мне нужно показывать квест только если он был выполнен < MaxRepeats раз. То есть для каждого из квестов сделать подзапрос, который посчитает количество HistoryItem-ов в которых в поле Quest записан даный квест. Как это сделать?

Пока что у меня просто наработка из рандомного кода т.к. я не понимаю как конкретно эта запись должна выглядеть в принципе:

var history = _db.Realm.All<HistoryItem>().Where(a => a.Quest != null).GroupBy(a=>a.Quest);
var tmp = _db.Realm.All<Quest>().Where(a =>
                              a.StartDate < startDayIsLessThan &&
                              a.EndDate > EndDateIsHigherThan);

Я нашел синтаксис подзапросов. Например, следующий запрос находит людей, которые имеют больше 3х невакцинированных собак:

realm.All<Person>()
    .Filter("SUBQUERY(Dogs, $dog, $dog.Vaccinated == false).@count > 3")
Answer 1

Мне кажется вы двигались в правильном направлении.

    var histCount = _db.Realm.All<HistoryItem>()
        .GroupBy(h => h.Quest)
        .Select(gr => new {Q = gr.Key, Count = gr.Count()});
    var result = _db.Realm.All<Quest>()
        // сокращаем коллекцию до join
        .Where(q => q.StartDate > start && q.EndDate < end) // todo: перепроверить условие 
        // join с группированной коллекцией элементов истории
        .Join(histCount,
            quest => quest.Id,
            hCount => hCount.Q,
            (quest, hCount) => new {Quest = quest, HCount = hCount.Count})
        // фильтрация по условиям кол-ва элементов
        .Where(it => it.HCount < it.Quest.MaxRepeats)
        // выборка результата
        .Select(it => it.Quest)
        .ToList();
Answer 2

Нужно было сделать обратный линк внутри Quest от HistoryItem (раньше был только прямой с HistoryItem в Quest)

public class Quest : RealmObject
{
    [PrimaryKey]
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public string Name { get; set; }
    public int MaxRepeats { get; set; } 
    [Backlink(nameof(HistoryItem.Quest))]
    public IQueryable<HistoryItem> HistoryItems{ get; }       
}
public class HistoryItem : RealmObject
{
    [PrimaryKey]
    public string Id { get; set; } = Guid.NewGuid().ToString();
    public DateTimeOffset DoneTime { get; set; }
    public Quest Quest { get; set; }
}

А дальше использовать запрос с фильтром:

_db.Realm.All<Quest>().Filter("HistoryItems.@count <= MaxRepeats");

Ну и в моем случае еще нужно было игнорировать случаи когда максРипитс равен 0:

_db.Realm.All<Quest>().Filter("MaxRepeats == 0 OR HistoryItems.@count <= MaxRepeats");
READ ALSO
Удалить ребра графа

Удалить ребра графа

Делаю мини игру на wpf

159
JSON не хочет парситься в класс! C#

JSON не хочет парситься в класс! C#

Делаю бота ТелеграммПри парсинге через Newtonsoft

132
Как в коде определить что свойство объекта является итерируемым?

Как в коде определить что свойство объекта является итерируемым?

Хочу сделать универсальный метод выгружающий таблицу в pdf

147