查询RavenDB以查找包含特定值的子属性集合

本文关键字:属性 集合 RavenDB 查找 包含特 查询 | 更新日期: 2023-09-27 18:07:30

我有这个类,我们称它为"Device"。这个类有几个属性,其中一个是(字符串值的(集合属性。

在RavenDB中,可能有5000个"Device"实例,其中每个实例的集合属性中都可以有一个字符串值列表。让我们将此属性称为"MyStringValues"。我的问题围绕着在ravendb中搜索在其集合属性中包含字符串值的Device实例的最佳方法。

一个非常简单的例子:

void Main()
{
    var d1 = new Device();
    d1.Id = "device-1";
    d1.MyStringValues.Add("123");
    d2.MyStringValues.Add("456");
    var d2 = new Device();
    d2.Id = "device-2";
    d2.MyStringValues.Add("789");
    d2.MyStringValues.Add("abc");
}
public class Device{
    public Device(){
        MyStringValues = new List<string>();
    }
    public string Id {get;set;}
    public IList<string> MyStringValues {get;set;}
}

在我试图构造的方法中,我传递了一个字符串值。基于该字符串,我想接收一个设备。检索此"设备"的最佳方式是什么?由于设备的数量可能高达5000台,我无法将它们全部取出并开始循环使用。必须有更好(更快(的方法来做到这一点。伙计们,你们觉得怎么样?

查询RavenDB以查找包含特定值的子属性集合

您可以创建一个与MyStringValues列表匹配的索引,然后使用LINQ的Any进行查询。

您的索引将类似于:

public class Devices_ByStringValue : AbstractIndexCreationTask<Device>
{
    public override string IndexName => "Devices/ByStringValue";
    public Devices_ByStringValue()
    {
        Map = devices => from device in devices
                          select new { device.MyStringValues };
    }
}

现在你可以像这样查询:

var devices = session.Query<Device>()
        .Where(x => x.MyStringValues.Any(s => s == searchTerm))
        .ToList();

下面是一个完整的控制台应用程序示例:

class Program
{
    static void Main(string[] args)
    {
        Console.Write("> Enter your search term: ");
        var searchTerm = Console.ReadLine();
        using (var session = DocumentStoreHolder.Instance.OpenSession())
        {
            var devices = session.Query<Device>()
                .Where(x => x.MyStringValues.Any(s => s == searchTerm))
                .ToList();
            foreach (var device in devices)
            {
                Console.WriteLine(device.Id);
                foreach (var s in device.MyStringValues)
                    Console.WriteLine($" - {s}");
            }
        }
        Console.ReadKey();
    }
}
public class Device
{
    public Device()
    {
        MyStringValues = new List<string>();
    }
    public string Id { get; set; }
    public IList<string> MyStringValues { get; set; }
}
public class Devices_ByStringValue : AbstractIndexCreationTask<Device>
{
    public override string IndexName => "Devices/ByStringValue";
    public Devices_ByStringValue()
    {
        Map = devices => from device in devices
                          select new { device.MyStringValues };
    }
}
public class DocumentStoreHolder
{
    static DocumentStoreHolder()
    {
        Instance = new DocumentStore
        {
            Url = "http://localhost:8080/",
            DefaultDatabase = "RavenTest",
        };
        Instance.Initialize();
        Serializer = Instance.Conventions.CreateSerializer();
        Serializer.TypeNameHandling = TypeNameHandling.All;
        Instance.Initialize();
        IndexCreation.CreateIndexes(typeof(Devices_ByStringValue).GetTypeInfo().Assembly, Instance);
    }
    public static DocumentStore Instance { get; }
    public static JsonSerializer Serializer { get; }
}

创建一个索引,该索引将包含MyStringValues中的数据。它可以在一个数组中为每个记录包含多个值。

然后,您可以创建一个索引查询,并使用.Where(x => x.MyStringValues.Contains(filteredValue))仅筛选包含给定值的记录。

然后使用流式传输(如果匹配记录的数量可能很高(或使用load(您知道要加载的文档的上限(加载所有匹配的文档。

要在studio中测试索引,可以使用简单的MyStringValues:abc查询来查询索引。