【问题标题】:"Traditional" one-to-many Query with RavenDB使用 RavenDB 的“传统”一对多查询
【发布时间】:2021-10-21 15:23:35
【问题描述】:

我知道 RavenDB 的include-特性。它允许我在一次往返数据库的过程中立即获取引用的文档。但我的问题是:我首先获取的文档不包括对“其他”文档的引用。但是“其他”文档引用了当前文档。

想象一下我们在世界各地都有站点的设置。每个site 都可能触发各种警报。每个alarm 都通过siteId 引用site

现在我想获取所有站点的列表,包括所有警报。但看起来,这对 RavenDB 来说是不可能的吗?由于include 仅接受site-Document 中的“路径”,该路径包含引用文档的id(或id 数组)。

这可以通过在site'-document and referencing this array in include. But in contrast to a lot of examples featuring stuff like an orderwithlineItemswhere the order is a self contained thing, mysite` 中提供一组alarmIds 来解决,该数组将运行多年,收集0 到100 万之间的警报。这对我来说似乎是个坏主意。

当然我可以反过来:通过sitesId 查询所有警报和include 站点。但这不会返回警报为零的站点。

所以这只是我的设计错误吗?我误解了什么?还是不能在一个查询中执行此操作并防止“n+1 查询”?

【问题讨论】:

    标签: node.js nosql ravendb select-n-plus-1


    【解决方案1】:
    public class A
    {
        public string Id { get; set; }
    }
    
    public class B
    {
        public string Id { get; set; }
        public string A { get; set; }
    }
    
    public class MultiMapIndex : AbstractMultiMapIndexCreationTask<MultiMapIndex.Result>
    {
        public class Result
        {
            public string Id { get; set; }
            public IEnumerable<string> Bs { get; set; }
        }
    
        public MultiMapIndex()
        {
            AddMap<A>(items => from a in items
                select new Result {Id = a.Id, Bs = new string[0]});
    
            AddMap<B>(items => from b in items
                select new Result {Id = b.A, Bs = new[] {b.Id}});
    
            Reduce = results => from result in results
                group result by result.Id
                into g
                select new Result {Id = g.Key, Bs = g.SelectMany(r => r.Bs)};
        }
    }
    
    [Fact]
    public async Task TestCase()
    {
        using var store = GetDocumentStore();
    
        await new MultiMapIndex().ExecuteAsync(store);
        using (var session = store.OpenAsyncSession())
        {
            await session.StoreAsync(new B {A = "a/1"}, "b/0");
            await session.StoreAsync(new A(), "a/1");
            await session.StoreAsync(new A(), "a/2");
            await session.SaveChangesAsync();
        }
    
        WaitForIndexing(store);
    
        using (var session = store.OpenAsyncSession())
        {
            var results = await session.Query<MultiMapIndex.Result, MultiMapIndex>()
                .Include(r => r.Bs)
                .ToArrayAsync();
    
            var before = session.Advanced.NumberOfRequests;
    
            var bs = session.LoadAsync<B>(results[0].Bs);
    
            Assert.Equal(before, session.Advanced.NumberOfRequests);
        }
    }
    

    【讨论】:

    • 嗨!这看起来很有趣!我将更深入地了解 MultiMapIndexes。并希望通过 node.js 像这样使用它。 ;)
    【解决方案2】:

    如果您确实选择查询所有Alarms,正如您提到的,
    然后您可以在将按站点分组的警报集合上创建一个Map-Reduce index
    然后您可以查询此 Map-Reduce 索引 并了解每个站点它拥有或不拥有的警报数量...

    https://demo.ravendb.net/demos/csharp/static-indexes/map-reduce-index

    【讨论】:

    • 好的,我可以很容易地得到每个站点的alarmCount,很好。但是我仍然不能一口气包含这个结果?相反,我需要获取所有站点,然后再次获取每个站点的计数(现在我回到了 n+1 查询问题)
    猜你喜欢
    • 2011-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    • 2015-01-02
    • 2012-11-08
    • 1970-01-01
    相关资源
    最近更新 更多