我正在使用与存储在集合属性中的对象松散相关的术语“子文档”。鉴于这两个类:
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public IList<Bar> Bars { get; set; }
}
public class Bar
{
public string Name { get; set; }
public string Description { get; set; }
public string SomeString { get; set; }
public int SomeInt { get; set; }
}
我想在Name或Description属性中查询名称为“roses”的Bars。请注意,条形图存储在Foo中。
这是一个双重问题:
关于#1,我知道MongoDB中不可能有这样的东西,我要么必须单独存储Foo和Bar,要么查询Foos,其中任何一个Bars在名称中都有“玫瑰”,然后对它做一些事情在客户端上。但是RavenDB有Live Projections / TransformResults,所以我认为这也许是可能的。
答案 0 :(得分:2)
您可以使用索引将每个Bar的副本存储在字段存储中,是的 - 可以完成。但是你应该确保你理解这样做的影响。
通常,当您从raven查询时,索引仅用于确定哪些文档被发回。文档本身不是来自索引,而是来自文档存储。文档存储具有ACID保证 - 这意味着无论索引的状态如何,您始终都会获得文档的最新副本。如果您从索引条目或索引字段存储进行投影,那么您获得的值与索引本身一样陈旧。
假设您不断更新Bars,并在索引赶上上次更新之前进行搜索。你可以找回一个有旧数据的Bar。因此,您需要在结果中权衡数据的潜在陈旧性,可能使用WaitForNonStaleResultsAsOf...
个自定义之一 - 如果您正在进行大量写操作,这将降低搜索结果返回的速度。
public class Foos_BarsByName
: AbstractIndexCreationTask<Foo, Foos_BarsByName.Result>
{
public class Result
{
public string Name { get; set; }
public Bar Bar { get; set; }
}
public Foos_BarsByName()
{
Map = foos => from foo in foos
from bar in foo.Bars
select new
{
bar.Name,
Bar = bar
};
Index(x => x.Name, FieldIndexing.Analyzed);
Index(x => x.Bar, FieldIndexing.No);
Store(x => x.Bar, FieldStorage.Yes);
}
}
var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>()
.Customize(x => x.WaitForNonStaleResultsAsOfNow())
.Search(x => x.Name, "roses")
.Select(x => x.Bar);
处理它的另一种方法可能是让所有Foos回来,然后在客户端拉出你感兴趣的Bars。至少那时,一切都来自文档存储:
public class Foos_BarsByName
: AbstractIndexCreationTask<Foo, Foos_BarsByName.Result>
{
public class Result
{
public string Name { get; set; }
}
public Foos_BarsByName()
{
Map = foos => from foo in foos
from bar in foo.Bars
select new
{
bar.Name
};
Index(x => x.Name, FieldIndexing.Analyzed);
}
}
var results = session.Query<Foos_BarsByName.Result, Foos_BarsByName>()
.Search(x => x.Name, "roses")
.As<Foo>()
.AsEnumerable()
.SelectMany(x => x.Bars)
.Where(x => x.Name.IndexOf("roses",
StringComparison.CurrentCultureIgnoreCase)
!= -1)
.AsEnumerable()
将强制执行linq-to-raven查询,使得后续的所有内容都发生在客户端的linq-to-objects中。
当然,如果您正在进行比使用c#字符串函数表达更高级的搜索,那么您将无法采用第二种方法。