Запрос дочерней коллекции по нескольким значениям в RavenDB - PullRequest
6 голосов
/ 18 августа 2011

Я использую RavenDB build 371, и у меня есть следующая модель:

class Product {
 public string Id { get; set; }
 public ProductSpec[] Specs { get; set; }
}

class ProductSpec {
 public string Name { get; set; }
 public string Value { get; set; }
}

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

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .ToList();

Ожидаемые результаты возвращаются, однако при добавлении предиката дополнительной спецификации:

session.Query<Product>()
 .Where(product => product.Specs.Any(spec => spec.Name == "Color" && spec.Value == "Red"))
 .Where(product => product.Specs.Any(spec => spec.Name == "Country" && spec.Value == "US"))
 .ToList();

результаты не возвращаются, даже если результаты возвращеныпервый запрос содержит продукты с именем спецификации "Страна" и значением спецификации "США".Тот же результат наблюдается при использовании метода LuceneQuery.Похоже, что это похоже на это обсуждение , однако я не смог реализовать предложенное решение.В частности, после создания предлагаемого индекса я не знаю, как его запросить.

Как я могу поддержать этот тип запроса в RavenDB?

РЕДАКТИРОВАТЬ

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

class Product {
 public string Id { get; set; }
 public int CategoryId { get; set; }
 public string[] Specs { get; set; }
}

Для справки, исходная модель и запрос работают при использовании MongoDB с их индексной функцией multikeys .Очень удивительная проблема с MongoDB заключается в том, что операция count () медленная для запросов индекса .Этот тип запроса важен для разбиения на страницы, и хотя счет может быть кэширован, я хотел бы получить решение, которое предоставляет это из коробки.Кроме того, еще одно требование, которое у меня есть, - возможность агрегировать группы спецификаций для произвольных коллекций продуктов (например, чтобы получить коллекцию всех комбинаций спецификация / значение для продуктов в данной категории).В MongoDB это может быть достигнуто с помощью их функциональности MapReduce, однако результаты операции MapReduce являются статическими и должны обновляться вручную при изменении исходных данных, тогда как RavenDB автоматически обновляет индексы MapReduce в фоновом режиме.Таким образом, даже несмотря на то, что объявление индексов MapReduce в RavenDB более громоздко, чем в MongoDB IMO, автоматическое обновление фона перевешивает недостатки в долгосрочной перспективе.Я буду смотреть на CouchDB , поскольку их представления также обновляются автоматически, хотя, по-видимому, они обновляются по требованию, а не автоматически в фоновом режиме, не уверенный, будет ли это проблемой.

Ответы [ 3 ]

3 голосов
/ 27 марта 2012

В соответствии со сборкой 717 вы можете сделать это с помощью новой функции .Intersect(), которую сделал Мэтт Уоррен. Взгляните сюда: http://issues.hibernatingrhinos.com/issue/RavenDB-51

3 голосов
/ 18 августа 2011

Я пробовал разные вещи и не мог заставить его работать. Конкретный запрос, который вы пытаетесь выполнить, разрешается этим запросом Lucene RavenDB (в версии 426):

"{(Имя: Цвет И Значение: Красный) И (Имя: Страна И Значение: США)}", что объясняет, почему вы не получите результат.

После поиска в теме я нашел этот пост: Синтаксис запроса Lucene

Различные ответы предлагаются в ответах. Надеюсь, это поможет. Мне, конечно, любопытно, если это действительно невозможно.

1 голос
/ 07 октября 2011

Я немного изменил модель и смог достичь желаемого результата, используя метод Project в AbstractIndexCreationTask. Это (упрощенная) модель данных:

public class Product
{
    public string Id { get; set; }
    public int CategoryId { get; set; }
    public int TotalSold { get; set; }
    public Dictionary<string, string> Specs { get; set; }
}

Это определение индекса:

public class Products_ByCategoryIdAndSpecs_SortByTotalSold : AbstractIndexCreationTask<Product>
{
    public Products_ByCategoryIdAndSpecs_SortByTotalSold()
    {
        this.Map = products => from product in products
                               select new
                               {
                                   product.CategoryId,
                                   _ = Project(product.Specs, spec => new Field("Spec_" + spec.Key, spec.Value, Field.Store.NO, Field.Index.ANALYZED)),
                                   product.TotalSold
                               };
    }
}

Тогда я могу запросить примерно так:

    var results = session.Advanced.LuceneQuery<Product, Products_ByCategoryIdAndSpecs_SortByTotalSold>()
        .WhereEquals("CategoryId", 15920)
        .AndAlso().WhereEquals("Spec_Class", "3A")
        .AndAlso().WhereEquals("Spec_Finish", "Plain")
        .OrderBy("-TotalSold")
        .ToList(); 

При этом будут возвращены продукты в категории "15920", которые имеют спецификационное значение "Class" "3A" и спецификационное значение "Finish" "Plain", отсортированные в порядке убывания по общему количеству проданных единиц.

Ключ использовал метод Project, который в основном создает поля в документе Lucene для каждой пары имя-значение спецификации.

...