【问题标题】:How to create an RavenDb Index that gets the latest version of a category?如何创建获取最新版本类别的 RavenDb 索引?
【发布时间】:2013-11-05 13:46:27
【问题描述】:

与本题相关:RavenDB Get By List of IDs? 我所拥有的不起作用:

public class Entity
{
    public int CategoryId; //Unique identifier for the category the price applies to.
    public int Price; //Changes with time
    public DateTime Timestamp; //DateTime.UtcNow
}
public class LastEntityIndex : AbstractIndexCreationTask<Entity, Entity>
{
    public LastEntityIndex()
    {
        Map = prices => prices.Select(a => new { a.CategoryId, a.Price, a.Timestamp });

        Reduce = prices => from price in prices
                           group price by price.CategoryId
                                 into g
                                 let a = g.OrderByDescending(a => a.Timestamp).FirstOrDefault()
                                 select new
                                 {
                                     a.CategoryId,
                                     a.Price,
                                     a.Timestamp
                                 };
    }
}
public class LastEntity
{
    public int CategoryId;
    public DateTime Timestamp;
    public Entity LastEntity;
}
public class LastReportIndex : AbstractIndexCreationTask<Entity, LastEntity>
{
    public LastReportIndex()
    {
        Map = reports => reports.Select(a => new { a.CategoryId, a.Timestamp, LastEntity = a });

        Reduce = reports => from report in reports
                            group report by report.CategoryId
                                into g
                                let a = g.OrderByDescending(a => a.Timestamp).FirstOrDefault()
                                select new
                                {
                                    a.CategoryId,
                                    a.Timestamp,
                                    a.LastEntity
                                };
    }
}

我想创建一个索引来获取每个类别的最新记录。但以上都不起作用。非常感谢任何帮助。为这个新项目离开 sql 并评估 Raven。到目前为止,它似乎非常强大并且可以满足我们的需求,但是从 sql dbs 转变范式很难。

非常感谢。

PS 使用它来检索记录:

public List<Entity> GetLastEntityForCategoryIds(List<int> categoryIds)
    {
        using (var session = _documentStore.OpenSession())
        {
            return session.Query<LastEntity, LastReportIndex>()
                                    .Where(x => x.CategoryId.In(categoryIds))
                                    .Select(a => a.LastEntity)
                                    .ToList();
        }
    }

显然,“LastEntityIndex”不是我长期使用的东西(它只是为了尝试看看它是否有效),因为真正的实体有更多的字段,只有 3 个并将它们全部复制并维护它会非常努力。

【问题讨论】:

  • 什么不起作用?编译错误?错误的数据回来了?你能告诉我们什么数据回来了吗?您如何检查数据是否合法?索引是否仍然过时?
  • @Pure.Krome 索引不是陈旧的,(使用 WaitForNonStaleResultsAsOfNow 在单元测试中运行)。数据返回错误或所有默认值。
  • @RomanStefanidi 你能发布一个完整的单元测试的要点吗? This guide may help.

标签: c# .net ravendb


【解决方案1】:

您是正确的,您必须选择整个文档,而不是文档的部分。默认情况下,查询会返回整个文档。

如果您只想返回文档的一部分,则必须使用 projectionstransformers,或者像您一样获取整个文档,然后然后取出部分你想要的。

但是,你做了很多我认为没有必要的事情。例如,您在 reduce 中订购并获取单个项目。这不是索引的一个很好的用途。您可能应该只拥有一张简单的地图并根据您的查询进行排序。

请参阅this GIST 并阅读我的 cmets。那里还评论了其他一些内容。

也为你喝彩!

【讨论】:

    【解决方案2】:

    好吧,我知道发生了什么。 如果我对 Mapped/Reduced 查询执行 .Select,则返回默认值。 如果我这样做 .ToList().Select 或 Single() 等,我会得到正确的结果。

    这是我设置的一个单元测试,用于演示我在说什么。

    using Raven.Client.Indexes;
    using Raven.Tests.Helpers;
    using System;
    using System.Linq;
    using Xunit; //XUnit
    //using Microsoft.VisualStudio.TestTools.UnitTesting; //MSTest
    
    namespace RavenDBTest.Tests
    {
        //[TestClass] //MSTest
        public class RavenIndexTest : RavenTestBase
        {
            //[TestMethod] //MSTest
            [Fact] //XUnit
            public void CanIndexAndQuery()
            {
                var timestamp = DateTime.Now;
                var report1 = new Entity { CategoryId = 123, Price = 51, Timestamp = timestamp.AddSeconds(-20) };
                var report2 = new Entity { CategoryId = 123, Price = 62, Timestamp = timestamp.AddSeconds(-10) };
                var report3 = new Entity { CategoryId = 123, Price = 73, Timestamp = timestamp };
    
                using (var store = NewDocumentStore())
                {
                    new LatestEntity_Index().Execute(store);
    
                    using (var session = store.OpenSession())
                    {
                        session.Store(report1);
                        session.Store(report2);
                        session.Store(report3);
    
                        session.SaveChanges();
                    }
    
                    //WILL PASS
                    using (var session = store.OpenSession())
                    {
                        var result = session.Query<LastEntity, LatestEntity_Index>()
                            .Customize(customization => customization.WaitForNonStaleResultsAsOfNow())
                            .FirstOrDefault()
                            .LastReport;
    
                        AssertLatestResult(timestamp, result);
                    }
    
                    //WILL FAIL
                    using (var session = store.OpenSession())
                    {
                        var result = session.Query<LastEntity, LatestEntity_Index>()
                            .Customize(customization => customization.WaitForNonStaleResultsAsOfNow())
                            .Select(a => a.LastReport)
                            .FirstOrDefault();
    
                        AssertLatestResult(timestamp, result);
                    }
                }
            }
    
            private static void AssertLatestResult(DateTime timestamp, Entity result)
            {
                //MSTest:
                //Assert.AreEqual(123, result.CategoryId, "Category Does Not Match");
                //Assert.AreEqual(73, result.Price, "Latest Price Does Not Match");
                //Assert.AreEqual(timestamp, result.Timestamp, "Latest Timestamp Does Not Match");
    
                //XUnit:
                Assert.Equal(123, result.CategoryId);
                Assert.Equal(73, result.Price);
                Assert.Equal(timestamp, result.Timestamp);
            }
        }
    
        public class Entity
        {
            public int CategoryId {get;set;} //Unique identifier for the category the price applies to.
            public int Price {get;set;} //Changes with time
            public DateTime Timestamp {get;set;} //DateTime.UtcNow
        }
    
        public class LastEntity
        {
            public int CategoryId { get; set; }
            public DateTime Timestamp { get; set; }
            public Entity LastReport { get; set; }
        }
    
        public class LatestEntity_Index : AbstractIndexCreationTask<Entity, LastEntity>
        {
            public LatestEntity_Index()
            {
                Map = reports => from report in reports
                                 select new LastEntity
                                 {
                                     CategoryId = report.CategoryId,
                                     Timestamp = report.Timestamp,
                                     LastReport = report,
                                 };
    
                Reduce = reports => from report in reports
                                    group report by report.CategoryId
                                        into g
                                        let last = g.OrderBy(a=>a.Timestamp).Last()
                                        select new LastEntity
                                        {
                                            CategoryId = g.Key,
                                            Timestamp = last.Timestamp,
                                            LastReport = last.LastReport,
                                        };
            }
        }
    }
    

    我希望这对某人有所帮助。

    @Matt Johnson,这些索引的效率/糟糕程度如何?性能明智?和空间明智? 顺便为你的帮助干杯。 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-02
      相关资源
      最近更新 更多