2016-12-16 90 views
0

我認爲我的場景是任何應用程序中的常見場景。我將舉例說明使用一個常用的域:產品和訂單(產品)。如何通過RavenDb中的相關文檔字段創建搜索索引?

我試圖做的是按產品名稱搜索訂單,考慮到訂單有一個itens列表,每個項目都有一個相關的productId。

我做了一些搜索和閱讀Raven文檔,但我無法找到我的問題的答案。

請考慮下面的代碼:

public class Product 
    { 
     public string Id { get; set; } 
     public string ProductName { get; set; } 
     public decimal Price { get; set; } 
    } 

    public class Order 
    { 
     public string Id { get; set; } 
     public string OrderNumber { get; set; } 
     public decimal Total { get; set; } 
     public string Customer { get; set; } 
     public Item[] Items { get; set; } 
    } 

    public class Item 
    { 
     public string ProductId { get; set; } 
     public decimal Price { get; set; } 
     public int Quantity { get; set; } 
    } 


    public class Order_ByProductName : AbstractMultiMapIndexCreationTask<Order_ByProductName.Result> 
    { 
     public class Result 
     { 
      public string ProductId { get; set; } 
      public string ProductName { get; set; } 
      public string[] OrdersIds { get; set; } 
      public string[] OrdersNumbers { get; set; } 
     } 

     public Order_ByProductName() 
     { 
      AddMap<Product>(products => from product in products 
             select new 
             { 
              ProductId = product.Id, 
              ProductName = product.ProductName, 
              OrderId = default(string), 
              OrderNumber = default(string) 
             }); 

      AddMap<Order>(orders => from order in orders 
            group order by order.Items.Select(c => c.ProductId) 
            into g 
            select new 
            { 
             ProductId = g.Key, 
             ProductName = default(string), 
             OrdersIds = g.Select(c => c.Id), 
             OrdersNumbers = g.Select(c => c.OrderNumber) 
            }); 

      Reduce = results => from result in results 
           group result by result.ProductId 
           into g 
           select new 
           { 
            ProductId = g.Key, 
            ProductName = g.Select(r => r.ProductName).Where(t => t != null).First(), 
            OrdersIds = g.Where(r => r.OrdersIds != null).SelectMany(r => r.OrdersIds), 
            OrdersNumbers = g.Where(r => r.OrdersNumbers != null).SelectMany(r => r.OrdersNumbers) 
           }; 

      Sort("ProductName", SortOptions.String); 
      Index(x => x.ProductName, FieldIndexing.Analyzed); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var documentStore = new DocumentStore 
      { 
       Url = "http://localhost:8080", 
       DefaultDatabase = "MyDatabase" 
      }; 

      documentStore.Initialize(); 
      new Order_ByProductName().Execute(documentStore); 

      using (var session = documentStore.OpenSession()) 
      { 
       var product1 = new Product() { Price = 100, ProductName = "Phone" }; 
       var product2 = new Product() { Price = 1000, ProductName = "Laptop" }; 
       var product3 = new Product() { Price = 200, ProductName = "Windows Phone" }; 

       session.Store(product1); 
       session.Store(product2); 
       session.Store(product3); 
       session.SaveChanges(); 
      } 

      using (var session = documentStore.OpenSession()) 
      { 
       var products = session.Query<Product>().ToList(); 

       var order1 = new Order(); 
       order1.Customer = "Jhon Doe"; 
       order1.OrderNumber = "001"; 
       order1.Items = new Item[] { 
        new Item { ProductId = products[0].Id, Price = products[0].Price, Quantity = 1 }, 
        new Item { ProductId = products[1].Id, Price = products[1].Price, Quantity = 1 } 
       }; 
       order1.Total = order1.Items.Sum(c => (c.Quantity * c.Price)); 

       var order2 = new Order(); 
       order2.Customer = "Joan Doe"; 
       order2.OrderNumber = "002"; 
       order2.Items = new Item[] { 
        new Item { ProductId = products[2].Id, Price = products[2].Price, Quantity = 1 } 
       }; 
       order2.Total = order2.Items.Sum(c => (c.Quantity * c.Price)); 

       session.Store(order1); 
       session.Store(order2); 
       session.SaveChanges(); 
      } 

      using (var session = documentStore.OpenSession()) 
      { 
       var results = session 
        .Query<Order_ByProductName.Result, Order_ByProductName>() 
        .Where(x => x.ProductName == "Phone") 
        .ToList(); 

       foreach (var item in results) 
       { 
        Console.WriteLine($"{item.ProductName}\t{string.Join(", ", item.OrdersNumbers)}"); 
       } 

       Console.ReadKey(); 
      } 
     } 
    } 

我發現了一個相關的問題在這裏How to index related documents in reverse direction in Ravendb,但這種情況是有點不同。如果您評論索引創建,則會運行上述代碼,但會另外發出異常:「無法理解查詢:變量初始值設定項必須是選擇查詢表達式」。

我需要財產以後類似下面的SQL但RavenDb:

select pro.ProductName, ord.OrderNumber from orders ord 
inner join items itm on itm.OrderId = ord.Id 
inner join products pro on pro.Id = itm.ProductId 
where pro.ProductName like '%Phone%'; 

如何通過創建一個產品名稱搜索和返回RavenDb列表或訂單? 即時通訊使用版本3.5(.1)

考慮作爲主要問題搜索「相關實體屬性的實體」。

在此先感謝!

回答

2

請考慮將產品名稱直接存儲在訂單項中。這將有兩個好處 - 訂單項目不會受到後來產品更改的影響,索引將更便宜。

下面的代碼演示了這兩種方法:

public class Product 
{ 
    public string Id { get; set; } 
    public string ProductName { get; set; } 
    public decimal Price { get; set; } 
} 

public class Order 
{ 
    public string Id { get; set; } 
    public string OrderNumber { get; set; } 
    public decimal Total { get; set; } 
    public string Customer { get; set; } 
    public Item[] Items { get; set; } 
} 

public class Item 
{ 
    public string ProductId { get; set; } 
    public string ProductName { get; set; } 
    public decimal Price { get; set; } 
    public int Quantity { get; set; } 
} 

public class OrderView 
{ 
    public string OrderId { get; set; } 
    public string OrderNumber { get; set; } 
    public string[] ProductIds { get; set; } 
    public string[] ProductNames { get; set; } 
} 

public class Order_ByItemName : AbstractIndexCreationTask<Order, OrderView> 
{ 
    public Order_ByItemName() 
    { 
     Map = orders => from order in orders 
         select new 
         { 
          OrderId = order.Id, 
          OrderNumber = order.OrderNumber, 
          ProductIds = order.Items.Select(x => x.ProductId).ToArray(), 
          ProductNames = order.Items.Select(x => x.ProductName).ToArray(), 
         }; 

     Index(x => x.ProductNames, FieldIndexing.Analyzed); 
     StoreAllFields(FieldStorage.Yes); 
    } 
} 

public class Order_ByProductName : AbstractIndexCreationTask<Order, OrderView> 
{ 
    public Order_ByProductName() 
    { 
     Map = orders => from order in orders 
         let products = LoadDocument<Product>(order.Items.Select(x => x.ProductId)) 
         select new 
         { 
          OrderId = order.Id, 
          OrderNumber = order.OrderNumber, 
          ProductIds = products.Select(x => x.Id).ToArray(), 
          ProductNames = products.Select(x => x.ProductName).ToArray(), 
         }; 

     Index(x => x.ProductNames, FieldIndexing.Analyzed); 
     StoreAllFields(FieldStorage.Yes); 
    } 
} 

class Program 
{ 

    static void Main(string[] args) 
    { 
     var documentStore = new DocumentStore 
     { 
      Url = "http://localhost:8080", 
      DefaultDatabase = "MyDatabase" 
     }; 

     documentStore.Initialize(); 
     new Order_ByProductName().Execute(documentStore); 
     new Order_ByItemName().Execute(documentStore); 

     using (var session = documentStore.OpenSession()) 
     { 
      var product1 = new Product() { Id = "products/1", Price = 100, ProductName = "Phone" }; 
      var product2 = new Product() { Id = "products/2", Price = 1000, ProductName = "Laptop" }; 
      var product3 = new Product() { Id = "products/3", Price = 200, ProductName = "Windows Phone" }; 

      session.Store(product1); 
      session.Store(product2); 
      session.Store(product3); 
      session.SaveChanges(); 
     } 

     using (var session = documentStore.OpenSession()) 
     { 
      var products = session.Query<Product>().ToList(); 

      var order1 = new Order(); 
      order1.Id = "orders/1"; 
      order1.Customer = "Jhon Doe"; 
      order1.OrderNumber = "001"; 
      order1.Items = new Item[] { 
       new Item { ProductId = products[0].Id, ProductName = products[0].ProductName, Price = products[0].Price, Quantity = 1 }, 
       new Item { ProductId = products[1].Id, ProductName = products[1].ProductName, Price = products[1].Price, Quantity = 1 } 
      }; 
      order1.Total = order1.Items.Sum(c => (c.Quantity * c.Price)); 

      var order2 = new Order(); 
      order1.Id = "orders/1"; 
      order2.Customer = "Joan Doe"; 
      order2.OrderNumber = "002"; 
      order2.Items = new Item[] { 
       new Item { ProductId = products[2].Id, ProductName = products[2].ProductName, Price = products[2].Price, Quantity = 1 } 
      }; 
      order2.Total = order2.Items.Sum(c => (c.Quantity * c.Price)); 

      session.Store(order1); 
      session.Store(order2); 
      session.SaveChanges(); 
     } 
     Thread.Sleep(5000); // wait for indexing 

     using (var session = documentStore.OpenSession()) 
     { 
      var itemResults = session 
       .Query<OrderView, Order_ByItemName>() 
       .Search(x => x.ProductNames, "Phone") 
       .ProjectFromIndexFieldsInto<OrderView>() 
       .ToList(); 

      var results = session 
       .Query<OrderView, Order_ByProductName>() 
       .Search(x => x.ProductNames, "Phone") 
       .ProjectFromIndexFieldsInto<OrderView>() 
       .ToList(); 


      Console.WriteLine("Order_ByItemName"); 
      foreach (var order in itemResults) 
      { 
       Console.WriteLine($"OrderNumber: {order.OrderNumber}"); 
       for (int i = 0; i < order.ProductIds.Length; i++) 
       { 
        Console.WriteLine($"Item: {order.ProductIds[i]} - {order.ProductNames[i]}"); 
       } 
      } 

      Console.WriteLine("Order_ByProductName"); 
      foreach (var order in results) 
      { 
       Console.WriteLine($"OrderNumber: {order.OrderNumber}"); 
       for (int i = 0; i < order.ProductIds.Length; i++) 
       { 
        Console.WriteLine($"Item: {order.ProductIds[i]} - {order.ProductNames[i]}"); 
       } 
      } 

      Console.ReadKey(); 
     } 
    } 
} 
相關問題