Querying multiple fields easily using RavenDB

This one comes from Ayende’s book about RavenDB.

If you want to learn RavenDB basics, I would recommend you to subscribe RavenDB bootcamp (it’s free). But, if you want a deep dive, Ayende’s book is an excellent resource.

Consider this document:

{
    "Company": "companies/62",
    "Employee": "employees/7",
    "OrderedAt": "1997-01-07T00:00:00.0000000",
    "RequireAt": "1997-02-18T00:00:00.0000000",
    "ShippedAt": "1997-01-13T00:00:00.0000000",
    "ShipTo": {
        "Line1": "Alameda dos Canàrios, 891",
        "Line2": null,
        "City": "Sao Paulo",
        "Region": "SP",
        "PostalCode": "05487-020",
        "Country": "Brazil"
    },
    "ShipVia": "shippers/1",
    "Freight": 108.04,
    "Lines": [
        {
            "Product": "products/1",
            "ProductName": "Chai",
            "PricePerUnit": 14.4,
            "Quantity": 10,
            "Discount": 0
        },
        {
            "Product": "products/21",
            "ProductName": "Sir Rodney's Scones",
            "PricePerUnit": 8,
            "Quantity": 30,
            "Discount": 0.1
        },
        {
            "Product": "products/28",
            "ProductName": "Rössle Sauerkraut",
            "PricePerUnit": 36.4,
            "Quantity": 42,
            "Discount": 0.1
        },
        {
            "Product": "products/36",
            "ProductName": "Inlagd Sill",
            "PricePerUnit": 15.2,
            "Quantity": 5,
            "Discount": 0.1
        },
        {
            "Product": "products/40",
            "ProductName": "Boston Crab Meat",
            "PricePerUnit": 14.7,
            "Quantity": 2,
            "Discount": 0.1
        }
    ]
}

What if we want to get all orders that have a particular product? How would be the query?

var q =
    from order in session.Query<Order>()
    where order.Lines.Any(x => x.Product == "products/1")
    select order;

Pretty simple, huh?! But, as you know, all RavenDB queries will use an index. If there is no index to support a query, RavenDB will generate one automatically for you.

Here is the map of the index created by RavenDB to support this query.

from doc in docs.Orders
select new {
	Lines_Product = (
		from docLinesItem in ((IEnumerable<dynamic>)doc.Lines).DefaultIfEmpty()
		select docLinesItem.Product).ToArray()
}

The interesting thing here is the use of an array of strings. When RavenDB encounters a collection in the index entry fields, it is actually indexing that field multiple times. Another important idea is that RavenDB will flatten out collections.

So, let’s define an index ourselves.

public class Orders_SearchByProduct :
    AbstractIndexCreationTask<Order, Orders_SearchByProduct.QueryModel>
{
    public class QueryModel
    {
        public string Query;
    }

    public Orders_SearchByProduct()
    {
        Map = orders =>
            from order in orders
            select new
            {
                Query = new object[]
                {
                    order.Lines.Select(p => p.Product).ToArray(),
                    order.Lines.Select(p => p.ProductName).ToArray()
                }
            };
    }
}

Now we can search orders that have a specific product considering his Id or name.

This is how we do the query.

using (var session = DocumentStoreHolder.Store.OpenSession())
{
    var q =
        session.Query<Orders_SearchByProduct.QueryModel,Orders_SearchByProduct>()
            .Where(o => o.Query == "Manjimup Dried Apples")
            .OfType<Order>();
                    
    foreach (var order in q.ToList())
    {
        Console.WriteLine(order.Id);
    }
}

Here we are using the OfType operator to change the result to the appopriate returned type.

That’s all.

Compartilhe este insight:

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Nos últimos dois posts demonstrei como as alocações podem implicar em penalidades de performance. Nesse post, parto, novamente, de código...
Há, muito, muito tempo atrás Em 2002, conheci o projeto SharpDevelop – uma ousada tentativa de criar, do zero, em...
Nunca trabalhei em um circo, tampouco criei elefantes! Portanto, advirto que os “fatos” que lerá aqui foram relatados por amigos,...
In the previous post, I shared some good things about our new query language: RQL. Now, I will show you...
No post anterior, apresentamos o Apache NiFi e entendemos como é possível integrar aplicações através de fluxos de dados nessa...
Neste post, vou compartilhar como dar os primeiros passos com OpenCV, rapidamente, usando Visual Studio 2017 e VcPkg. O que...
Masterclass

O Poder do Metamodelo para Profissionais Técnicos Avançarem

Nesta masterclass aberta ao público, vamos explorar como o Metamodelo para a Criação, desenvolvido por Elemar Júnior, pode ser uma ferramenta poderosa para alavancar sua carreira técnica em TI.

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

× Precisa de ajuda?