在 RavenDB 中查询包含特定值的子 属性 集合
Query RavenDB for child property collection that contains certain value
我有这个 class,我们称它为“设备”。这个 class 有几个属性,其中一个是集合 属性(字符串值)。
在 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 个,我无法获取所有设备并开始遍历它们。必须有更好(更快)的方法来做到这一点。
大家怎么看?
创建一个包含来自 MyStringValues 的数据的索引。它可以在数组中为每条记录包含多个值。
然后您可以创建索引查询并使用 .Where(x => x.MyStringValues.Contains(filteredValue))
过滤仅包含给定值的记录。
然后使用流式处理(如果匹配记录的数量可能很多)或使用加载(您知道要加载的文档的上限)加载所有匹配的文档。
要在工作室中测试索引,您可以使用简单的 MyStringValues:abc
查询来查询索引。
您可以创建一个与您的 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; }
}
我有这个 class,我们称它为“设备”。这个 class 有几个属性,其中一个是集合 属性(字符串值)。
在 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 个,我无法获取所有设备并开始遍历它们。必须有更好(更快)的方法来做到这一点。 大家怎么看?
创建一个包含来自 MyStringValues 的数据的索引。它可以在数组中为每条记录包含多个值。
然后您可以创建索引查询并使用 .Where(x => x.MyStringValues.Contains(filteredValue))
过滤仅包含给定值的记录。
然后使用流式处理(如果匹配记录的数量可能很多)或使用加载(您知道要加载的文档的上限)加载所有匹配的文档。
要在工作室中测试索引,您可以使用简单的 MyStringValues:abc
查询来查询索引。
您可以创建一个与您的 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; }
}