Raven在OrderByDescending Statement中返回错误的文档

时间:2014-05-30 12:06:24

标签: c# ravendb

我的raven数据库中有50,000个文档,但是当II运行此查询时,latestProfile对象的Id返回为9999(db中的第一个id为0,因此这是第10,000个项目)

    //find the profile with the highest ID now existing in the collection
    var latestProfile = session.Query<SiteProfile>()
        .Customize(c => c.WaitForNonStaleResults())
        .OrderByDescending(p => p.Id)
        .FirstOrDefault();

    //lastProfile.Id is 9999 here

    //See how many items there are in the collection. This returns 50,000
    var count = session.Query<SiteProfile>()
        .Customize(c => c.WaitForNonStaleResults()).Count();

我的猜测是Raven在我的OrderByDescending语句之前分页,但是

  1. 默认页面大小为10,甚至最大值为1024
  2. 此部分的所有部分均为IRavenQueryableIQueryable
  3. 它也是不是陈旧的索引,因为我用WaitForNonStaleResults()
  4. 对此进行了测试

    我的预期结果是我添加的最新ID(50,000)作为此处返回的项目,但实际上并非如此。

    为什么不呢?对我来说,这看起来像Raven中的一个错误。

    编辑:

    好的,所以我现在确切地知道为什么,但它仍然看起来像一个bug。以下是ToArray()

    实现的同一列表中的项目列表
    { Id = 9999 },
    { Id = 9998 },
    { Id = 9997 },
    { Id = 9996 },
    { Id = 9995 },
    { Id = 9994 },
    { Id = 9993 },
    { Id = 9992 },
    { Id = 9991 },
    { Id = 9990 },
    { Id = 999 },    //<-- Whoops! This is text order not int order
    { Id = 9989 }, 
    

    所以即使我的Id列是整数,因为Raven在内部将其存储为字符串,它按照该表示进行排序。显然,Ravens Queryable实现在检查类型

    之前解析了排序

    我已经读过您可以定义排序顺序以对已定义的索引使用整数排序,但实际上,这应该无关紧要。在强类型语言中,整数应按整数排序。

    有没有办法让这个Id订购正确?我是否真的不得不求助于在id列上创建一个特殊的索引才能正确地排序整数?

    更新2:

    我现在使用索引如下:

        public SiteProfiles_ByProfileId()
        {
            Map = profiles => from profile in profiles
                           select new
                           {
                               profile.Id
                           };
    
            Sort(x => x.Id, SortOptions.Int);
        }
    

    尝试强制它理解整数。我可以看到我的索引是通过Raven服务器控制台调用的,如下所示:

    Request # 249: GET     -     3 ms - Bede.Profiles - 200 -     /indexes/SiteProfiles/ByProfileId?&pageSize=1&sort=-__document_id&operationHeadersHash=-1789353429
        Query:
        Time: 3 ms
        Index: SiteProfiles/ByProfileId
        Results: 1 returned out of 20,000 total.
    

    仍然它返回字符串排序结果。我已经看到了不使用整数作为id的建议,但是这会导致这个项目出现大量问题,因为第三方引用了当前的id(在旧服务中这是为了取代)。

    更新3:我有特定的单元测试来显示问题。它似乎适用于任何整数属性,除了Id。

        [TestMethod]
        public void Test_IndexAllowsCorrectIntSortingWhenNotId()
        {
            using (var store = new EmbeddableDocumentStore() {RunInMemory = true})
            {
                store.Initialize();
                IndexCreation.CreateIndexes(typeof(MyFakeProfiles_ByProfileId).Assembly, store);
    
                using (var session = store.OpenSession())
                {
                    var profiles = new List<MyFakeProfile>()
                    {
                        new MyFakeProfile() { Id=80, Age = 80, FirstName = "Grandpa", LastName = "Joe"},
                        new MyFakeProfile() { Id=9, Age = 9,FirstName = "Jonny", LastName = "Boy"},
                        new MyFakeProfile() { Id=22, Age = 22, FirstName = "John", LastName = "Smith"}
                    };
    
                    foreach (var myFakeProfile in profiles)
                    {
                        session.Store(myFakeProfile, "MyFakeProfiles/" + myFakeProfile.Id);
                    }
                    session.SaveChanges();
    
                    var oldestPerson = session.Query<MyFakeProfile>().Customize(c => c.WaitForNonStaleResults())
                        .OrderByDescending(p => p.Age).FirstOrDefault();
    
                    var youngestPerson = session.Query<MyFakeProfile>().Customize(c => c.WaitForNonStaleResults())
                        .OrderBy(p => p.Age).FirstOrDefault();
    
                    var highestId = session.Query<MyFakeProfile>("MyFakeProfiles/ByProfileId").Customize(c => c.WaitForNonStaleResults())
                        .OrderByDescending(p => p.Id).FirstOrDefault();
    
                    var lowestId = session.Query<MyFakeProfile>("MyFakeProfiles/ByProfileId").Customize(c => c.WaitForNonStaleResults())
                        .OrderBy(p => p.Id).FirstOrDefault();
    
                    //sanity checks for ordering in Raven
                    Assert.AreEqual(80,oldestPerson.Age); //succeeds
                    Assert.AreEqual(9, youngestPerson.Age);//succeeds
                    Assert.AreEqual(80, highestId.Id);//fails
                    Assert.AreEqual(9, lowestId.Id);//fails
                }
            }
        }
    
        private void PopulateTestValues(IDocumentSession session)
        {
            var profiles = new List<MyFakeProfile>()
            {
                new MyFakeProfile() { Id=80, Age = 80, FirstName = "Grandpa", LastName = "Joe"},
                new MyFakeProfile() { Id=9, Age = 9,FirstName = "Jonny", LastName = "Boy"},
                new MyFakeProfile() { Id=22, Age = 22, FirstName = "John", LastName = "Smith"}
            };
    
            foreach (var myFakeProfile in profiles)
            {
                session.Store(myFakeProfile, "MyFakeProfiles/" + myFakeProfile.Id);
            }
        }
    }
    
    public class MyFakeProfile
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    
    public class MyFakeProfiles_ByProfileId : AbstractIndexCreationTask<MyFakeProfile>
    {
    
        // The index name generated by this is going to be SiteProfiles/ByProfileId
        public MyFakeProfiles_ByProfileId()
        {
            Map = profiles => from profile in profiles
                              select new
                              {
                                  profile.Id
                              };
    
            Sort(x => (int)x.Id, SortOptions.Int);
        }
    }
    

2 个答案:

答案 0 :(得分:0)

您需要在索引上指定字段的类型,请参阅http://ravendb.net/docs/2.5/client-api/querying/static-indexes/customizing-results-order

旁注,RavenDB中的ID 总是字符串。你似乎试图使用整数ID - 不要这样做。

答案 1 :(得分:0)

您可以提供多个Sort字段,因为您只为Id定义了字段:

public SiteProfiles_ByProfileId()
{
    Map = profiles => from profile in profiles
                   select new
                   {
                       profile.Id
                   };

    Sort(x => x.Id, SortOptions.Int);
    Sort(x => x.Age, SortOptions.Int);
}

但是 ...我不确定对未映射的字段应用排序的影响。

您可能需要扩展映射以选择这两个字段,如下所示:

public SiteProfiles_ByProfileId()
{
    Map = profiles => from profile in profiles
                   select new
                   {
                       profile.Id,
                       profile.Age
                   };

    Sort(x => x.Id, SortOptions.Int);
    Sort(x => x.Age, SortOptions.Int);
}