如何创建一个获取最新版本类别的RavenDb索引?

时间:2013-11-05 00:50:11

标签: c# .net ravendb

与此问题相关: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并且将它们全部复制并维护它非常努力

2 个答案:

答案 0 :(得分:1)

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

如果您只想返回文档的一部分,则必须使用projectionstransformers,或者按照您的方式行事并完成所有操作并然后拿出你想要的零件。

然而,你做了很多我认为不必要的事情。例如,您在reduce中订购并获取单个项目。这不是一个很好的索引使用。您可能只需要一个简单的地图并按查询进行排序。

请参阅this GIST并阅读我的评论。其他一些内容也在评论中。

也为你欢呼!

答案 1 :(得分:0)

是的,我弄清楚发生了什么。 如果我这样做。选择Mapped / Reduced查询,返回默认值。 如果我这样做.ToList()。选择或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,这些指数的效率/糟糕程度如何?表现明智吗?和太空明智吗? 顺便为你的帮助干杯。 :)