indexing - RavenDB:如何正确查询/过滤 MultiMapIndex 中的嵌套值?

标签 indexing ravendb

我的应用程序有一个要求,即应该能够通过相关联系人号码来过滤/搜索

Pair 始终存储对Contact 的引用,但联系人的号码不会也不会存储在该引用中。所以我尝试为此创建一个自定义索引,因为 PairContact 存储在不同的集合中。

索引的简化示例如下所示。

public class Pairs_Search : AbstractMultiMapIndexCreationTask<Pairs_Search.Result>
{
    public class Result
    {
        public string Id { get; set; }
        public string Workspace { get; set; }
        public ContactResult Contact { get; set; }
        public bool HasContactDetails { get; set; }
    }

    public class ContactResult
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public int Number { get; set; }
    }

    public Pairs_Search()
    {
        AddMap<Pair>(pairs => pairs
            .Select(p => new
                {
                    p.Id,
                    p.Workspace,
                    Contact = new
                    {
                        p.Contact.Id,
                        p.Contact.Name,
                        Number = 0
                    },
                    // Mark this items as WITHOUT contact details.
                    HasContactDetails = false,
                }
            )
        );

        AddMap<Contact>(contacts => contacts
            .Select(c => new
                {
                    Id = (string) null,
                    Workspace = (string) null,
                    Contact = new
                    {
                        c.Id,
                        Name = c.DisplayName,
                        c.Number
                    },
                    // Mark this items as WITH contact details.
                    HasContactDetails = true,
                }
            )
        );

        Reduce = results => results
            // First group by the contact ID. This will
            // create a group with 2 or more items. One with the contact
            // details, and one or more with pair details.
            // They are all marked by a boolean flag 'HasContactDetails'.
            .GroupBy(x => x.Contact.Id)
            // We are going to enrich each item in the current group, that is
            // marked as 'HasContactDetails = false', with the contact number.
            // We need that so that we can filter on it later.
            .Select(group =>
                group
                    .Select(i => new
                        {
                            i.Id,
                            i.Workspace,
                            Contact = new
                            {
                                i.Contact.Id,
                                i.Contact.Name,
                                // Does the current item have the contact details?
                                Number = i.HasContactDetails
                                    // Yes, in this case we use the previously set contact number.
                                    ? i.Contact.Number
                                    // No, find the item with the contact details and grab the number.
                                    : group.Single(x => x.HasContactDetails).Contact.Number
                            },
                            // Pass on the flag that indicates wheter or not
                            // this item has the contact details. We are going
                            // to need it later.
                            i.HasContactDetails
                        }
                    )
                    // We don't need the items with the contact details
                    // anymore, so filter them out.
                    .Where(x => !x.HasContactDetails)
            )
            // Flatten all the small lists to one big list.
            .SelectMany(x => x);

        // Mark the following fields of the result as searchable.
        Index(x => x.Contact.Number, FieldIndexing.Search);
    }
}

我已经设置了一个完整的示例来重现我遇到的问题。您可以找到示例 here .

创建索引工作正常。查询索引也可以正常工作,因为它正确匹配了配对和联系人,并用联系人的号码丰富了索引结果。但是,当我尝试在嵌套的 Number 属性上使用 .Where().Search() 时,它无法正确过滤结果数据集来自索引。

没有任何过滤的索引的工作方式如下面的代码示例所示(也可在完整示例中找到)。

private static async Task ThisOneWorks()
{
    using (var session = Store.OpenAsyncSession())
    {
        var results = await session
            .Query<Pairs_Search.Result, Pairs_Search>()
            .ToListAsync(); 

        LogResults("ThisOneWorks()", results);              
    }

    // Output:
    // ThisOneWorks(): Pair 'Harry Potter' with number '70'
    // ThisOneWorks(): Pair 'Harry Potter' with number '70'
    // ThisOneWorks(): Pair 'Hermione Granger' with number '71'
    // ThisOneWorks(): Pair 'Albus Dumbledore' with number '72'
}

对非嵌套值进行过滤也有效(在完整示例中也可用)。正如您所看到的,它过滤掉了具有不同工作区的工作区。

private static async Task ThisOneWithWorkspaceFilterWorks()
{
    using (var session = Store.OpenAsyncSession())
    {
        var results = await session                 
            .Query<Pairs_Search.Result, Pairs_Search>()
            .Where(x => x.Workspace == "hogwarts")
            .ToListAsync(); 

        LogResults("ThisOneWithWorkspaceFilterWorks()", results);               
    }

    // Output:
    // ThisOneWithWorkspaceFilterWorks(): Pair 'Harry Potter' with number '70'
    // ThisOneWithWorkspaceFilterWorks(): Pair 'Harry Potter' with number '70'
    // ThisOneWithWorkspaceFilterWorks(): Pair 'Hermione Granger' with number '71'
}

当我尝试过滤/搜索 WorkspaceNumber 属性时,我期望有两个与联系人 Harry Potter 相关的结果。但我只是得到一个空数据集。

private static async Task ThisOneWithWorkspaceAndNumberFilterDoesntWork()
{
    using (var session = Store.OpenAsyncSession())
    {
        var results = await session                 
            .Query<Pairs_Search.Result, Pairs_Search>()
            .Where(x => x.Workspace == "hogwarts")
            .Where(x => x.Contact.Number == 70)
            .ToListAsync(); 

        LogResults("ThisOneWithWorkspaceAndNumberFilterDoesntWork()", results);             
    }

    // Output:
    // ThisOneWithWorkspaceAndNumberFilterDoesntWork(): EMPTY RESULTS!
}

谁能告诉我我在这里做错了什么?任何帮助将不胜感激!

最佳答案

解决方法是将 ContactResult 存储在不同的集合中,
在本例中,这就是所谓的相关文档
当您创建索引时,您将“索引相关文档

从演示示例中学习:
https://demo.ravendb.net/demos/csharp/related-documents/index-related-documents
该示例针对基本 map 索引,但多 map 原理相同。

从索引类中删除公共(public)类ContactResult 并用类似以下内容定义索引:

         select new Result
        {
            ....
            Number = LoadDocument<Contact>(Pair.Contact).Number
            .... 
        }

关于indexing - RavenDB:如何正确查询/过滤 MultiMapIndex 中的嵌套值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62285344/

相关文章:

RavenDB 查询语言

python - 将多索引中的条件列与同一索引对齐时出现问题

php - 未定义索引 : query in, 将 mysql 转换为 mysqli

MongoDB:存储染色体/位置最有效的方法是什么

RavenDB 删除后返回陈旧的结果

indexing - 在 RavenDB 中创建更多类似的内容

mysql - Index Scope在Mysql中是如何工作的?

tomcat - 如何在 webapp 部署时创建 Lucene 内存索引

ravendb - RavenDB 订阅存储是 NServiceBus 的中心故障点吗?

ravendb - 没有有效的商业许可证无法设置 Windows 身份验证