从RavenDB检索整个数据采集(Retrieving entire data collection

2019-07-30 04:09发布

我有,我需要获取整个数据收集要求Users从RavenDB和比较检索到的结果与另一组数据集。 有近4000条记录这个特殊的收藏。

因为乌鸦是安全默认情况下,我不断收到一个例外要么Number of requests per session exceeded或返回的最大128个记录。

我不想属性设置Session.Advanced.MaxNumberOfRequestsPerSession到一个更高的价值。

什么查询我应该用得到的所有记录的计数? 什么是处理这种情况的理想的方法呢?

Answer 1:

您可以使用分页和一次读这1024项。

int start = 0;
while(true)
{
   var current = session.Query<User>().Take(1024).Skip(start).ToList();
   if(current.Count == 0)
          break;

   start+= current.Count;
   allUsers.AddRange(current);

}


Answer 2:

这个问题被张贴此功能是RavenDB可用之前,但如果任何人现在在此跌倒...

该鼓励的方式来做到这一点是通过流API 。 该RavenDB客户批量流,以便它可以自动“页”到/来自服务器的请求/响应。 如果您选择在使用流API,客户端会假定你“知道你在做什么”,不检查用于定期查询128/1024/30限制。

var query = session.Query<User>();
 
using (var enumerator = session.Advanced.Stream(query)) {
    while (enumerator.MoveNext()) {
        allUsers.Add(enumerator.Current.Document);
    }
}

var count = allUsers.Count;

提示:虽然这是解决问题的方式鼓励......作为一般规则,最好避免下手的情况。 如果有一百万条记录? 这allUsers名单将会获得巨大的。 也许一个索引或者变换可以先进行过滤出什么样的数据,你确实需要显示给用户/进程? 这是报告的目的呢? 也许RavenDB应该是自动导出到SQL服务器上报告服务? 等等...



Answer 3:

在Ayende答案建立,这里是一个完整的方法,这并克服每节30个查询,确实返回提供的类的所有文件的问题:

    public static List<T> getAll<T>(DocumentStore docDB) {
        return getAllFrom(0, new List<T>(), docDB);
    }

    public static List<T> getAllFrom<T>(int startFrom, List<T> list, DocumentStore docDB ) {
        var allUsers = list;

        using (var session = docDB.OpenSession())
        {
            int queryCount = 0;
            int start = startFrom;
            while (true)
            {
                var current = session.Query<T>().Take(1024).Skip(start).ToList();
                queryCount += 1;
                if (current.Count == 0)
                    break;

                start += current.Count;
                allUsers.AddRange(current);

                if (queryCount >= 30)
                {
                    return getAllFrom(start, allUsers, docDB);
                }
            }
        }
        return allUsers;
    }

我希望这不是太哈克做这样的。



Answer 4:

老实说,我更喜欢以下功能:

    public IEnumerable<T> GetAll<T>()
    {
        List<T> list = new List<T>();

        RavenQueryStatistics statistics = new RavenQueryStatistics();

        list.AddRange(_session.Query<T>().Statistics(out statistics));
        if (statistics.TotalResults > 128)
        {
            int toTake = statistics.TotalResults - 128;
            int taken = 128;
            while (toTake > 0)
            {
                list.AddRange(_session.Query<T>().Skip(taken).Take(toTake > 1024 ? 1024 : toTake));
                toTake -= 1024;
                taken += 1024;
            }
        }

        return list;
    }

[]的



Answer 5:

随着轻微扭动@ CAPAJ的帖子 。 这里是让所有的文档ID作为字符串列表的通用方法。 注意使用的Advanced.LuceneQuery<T>(idPropertyName) SelectFields<T>(idPropertyName)GetProperty(idPropertyName)使事情通用的。 默认是"Id"是有效的属性给定的<T>其应该是这样的时间99.999%)。 倘若你有一些其他财产作为你的Id ,你可以通过它为好。

public static List<string> getAllIds<T>(DocumentStore docDB, string idPropertyName = "Id") {
   return getAllIdsFrom<T>(0, new List<string>(), docDB, idPropertyName);
}

public static List<string> getAllIdsFrom<T>(int startFrom, List<string> list, DocumentStore docDB, string idPropertyName ) {
    var allUsers = list;

    using (var session = docDB.OpenSession())
    {
        int queryCount = 0;
        int start = startFrom;
        while (true)
        {
            var current = session.Advanced.LuceneQuery<T>().Take(1024).Skip(start).SelectFields<T>(idPropertyName).ToList();
            queryCount += 1;
            if (current.Count == 0)
                break;

            start += current.Count;
            allUsers.AddRange(current.Select(t => (t.GetType().GetProperty(idPropertyName).GetValue(t, null)).ToString()));

            if (queryCount >= 28)
            {
                return getAllIdsFrom<T>(start, allUsers, docDB, idPropertyName);
            }
        }
    }
    return allUsers;
}

在哪里/我如何使用,这是制作时的一个例子PatchRequest使用在RavenDb BulkInsert会议。 在某些情况下,我可能有成千上万的文件,并不能承受加载在内存中的所有文件只是为补丁操作再次重新在它们之间迭代......因此,只有他们的字符串ID的加载通入Patch命令。

void PatchRavenDocs()
{
    var store = new DocumentStore
    {
        Url = "http://localhost:8080",
        DefaultDatabase = "SoMeDaTaBaSeNaMe"
    };

    store.Initialize();

    // >>>here is where I get all the doc IDs for a given type<<<
    var allIds = getAllIds<SoMeDoCuMeNtTyPe>(store);    

    // create a new patch to ADD a new int property to my documents
    var patches = new[]{ new PatchRequest { Type = PatchCommandType.Set, Name = "SoMeNeWPrOpeRtY" ,Value = 0 }};

    using (var s = store.BulkInsert()){
        int cntr = 0;
        Console.WriteLine("ID Count " + allIds.Count);
        foreach(string id in allIds)
        {
            // apply the patch to my document
            s.DatabaseCommands.Patch(id, patches);

            // spit out a record every 2048 rows as a basic sanity check
            if ((cntr++ % 2048) == 0)
                Console.WriteLine(cntr + " " + id);
        }
    }
}

希望能帮助到你。 :)



Answer 6:

我喜欢把自己的ID,以完整的大型物体,而不是操作上的铝Dass的解决方案。 还可以直接从索引中获取的ID。 然而递归让我害怕位(尽管我认为这可能是好的),我删除了反映。

public List<string> GetAllIds<T>()
{
var allIds = new List<string>();
IDocumentSession session = null;

try
{
    session = documentStore.OpenSession();
    int queryCount = 0;
    int start = 0;
    while (true)
    {
        var current = session.Advanced.DocumentQuery<T>()
            .Take(1024)
            .Skip(start)
            .SelectFields<string>("__document_id")
            .AddOrder("__document_id")
            .ToList();

        if (current.Count == 0)
            break;
        allIds.AddRange(current);

        queryCount += 1;
        start += current.Count;

        if (queryCount == 30)
        {
            queryCount = 0;
            session.Dispose();
            session = documentStore.OpenSession();
        }
    }
}
finally
{
    if (session != null)
    {
        session.Dispose();
    }
}

return allIds;
}

此外,这是更新为ravendb 3



文章来源: Retrieving entire data collection from a RavenDB
标签: ravendb