用于额外计算的 RavenDb 映射索引
RavenDb map index for additional calculations
一开始我想说我对任何一种 NoSql 数据库都很陌生。我想我可能误解了 RavenDb 中索引的概念。
在我的应用程序中,我收集了代表汽车加油历史的文件(包括在此加油时所采取的路线的子集合)。简化版如下所示:
public class Fuel
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public IList<Route> Routes { get; set; }
}
public class Route
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
}
集合中的文档不会经常修改,所以我决定将所有计算都放入数据库中,而不是在每次请求时即时计算所有内容。但我不认为额外的计算字段应该在本文档中,因为它们将仅取决于现有值而不是由用户提供。我想到了 Map index
- 每次插入或修改文档时进行计算(以及将来可能的聚合)的非常好的方法。
我为索引
创建了另一个class
public class FuelCalculated
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public decimal? AverageFuelConsumption { get; set; }
public decimal? TotalCost { get; set; }
public IList<RouteCalculated> Routes { get; set; }
}
public class RouteCalculated
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
public decimal TotalDistance { get; set; }
public decimal AverageFuelConsumption { get; set; }
}
和索引定义:
public class FuelCalculatedIndex : AbstractIndexCreationTask<Fuel, FuelCalculated>
{
public FuelCalculatedIndex()
{
Map = fuels =>
fuels.Select(f => new FuelCalculated()
{
AverageFuelConsumption = (f.VolumeUsed * 100) / f.TotalDistance,
Routes = f.Routes.Select(r => new RouteCalculated()
{
StartingAddress = r.StartingAddress,
Stops = r.Stops,
TotalDistance = r.Stops.Sum(s => s.Distance),
AverageFuelConsumption = r.Stops.Sum(s => s.AverageFuelConsumption * s.Distance) / r.Stops.Sum(s => s.Distance),
}).ToList(),
TotalCost = f.VolumeUsed * f.CostPerLitre,
TotalDistance = f.TotalDistance,
VolumeUsed = f.VolumeUsed,
});
StoreAllFields(FieldStorage.Yes);
}
}
现在我不关心索引的数量 - 我想要显示所需的一切,因此查询不必跳转到原始文档。
现在,当我在代码中查询文档时,我在每个计算字段中得到空结果(或 0 对于不可空字段):
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.ToListAsync();
}
返回 JSON:
{
"volumeUsed":28.04,
"costPerLitre":4.93,
"totalDistance":467.3,
"totalCost":null, <----
"averageFuelConsumption":null, <----
"routes":[
{
"startingAddress":"Address 1",
"stops":[
{
"address":"Address 2",
"distance":351.0,
"averageFuelConsumption":6.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
},
{
"startingAddress":"Address 3",
"stops":[
{
"address":"Address 4",
"distance":116.3,
"averageFuelConsumption":7.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
}
]
}
当我在 Raven.Studio
中尝试简单的 RavenDb 查询并返回正确的值时,我真的很困惑
from index 'FuelCalculatedIndex'
select TotalCost
看来问题出在C#代码上。我做错了什么?
更新
我刚刚尝试在 C# 中运行原始查询:
await session
.Advanced.AsyncRawQuery<FuelCalculated>("from index 'FuelCalculatedIndex' select TotalCost")
.ToListAsync();
令人惊讶的是,它有效。
查询的结果始终是文档(地图索引)。
所以原来的查询实际上应该是:
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.As<Fuel>
.ToListAsync();
}
您需要使用 ProjectInto 才能获取存储的字段:
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.ProjectInto<FuelCalculated>
.ToListAsync();
}
一开始我想说我对任何一种 NoSql 数据库都很陌生。我想我可能误解了 RavenDb 中索引的概念。
在我的应用程序中,我收集了代表汽车加油历史的文件(包括在此加油时所采取的路线的子集合)。简化版如下所示:
public class Fuel
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public IList<Route> Routes { get; set; }
}
public class Route
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
}
集合中的文档不会经常修改,所以我决定将所有计算都放入数据库中,而不是在每次请求时即时计算所有内容。但我不认为额外的计算字段应该在本文档中,因为它们将仅取决于现有值而不是由用户提供。我想到了 Map index
- 每次插入或修改文档时进行计算(以及将来可能的聚合)的非常好的方法。
我为索引
创建了另一个classpublic class FuelCalculated
{
public decimal? VolumeUsed { get; set; }
public decimal CostPerLitre { get; set; }
public decimal? TotalDistance { get; set; }
public decimal? AverageFuelConsumption { get; set; }
public decimal? TotalCost { get; set; }
public IList<RouteCalculated> Routes { get; set; }
}
public class RouteCalculated
{
public string StartingAddress { get; set; }
public IList<Stop> Stops { get; set; }
public decimal TotalDistance { get; set; }
public decimal AverageFuelConsumption { get; set; }
}
和索引定义:
public class FuelCalculatedIndex : AbstractIndexCreationTask<Fuel, FuelCalculated>
{
public FuelCalculatedIndex()
{
Map = fuels =>
fuels.Select(f => new FuelCalculated()
{
AverageFuelConsumption = (f.VolumeUsed * 100) / f.TotalDistance,
Routes = f.Routes.Select(r => new RouteCalculated()
{
StartingAddress = r.StartingAddress,
Stops = r.Stops,
TotalDistance = r.Stops.Sum(s => s.Distance),
AverageFuelConsumption = r.Stops.Sum(s => s.AverageFuelConsumption * s.Distance) / r.Stops.Sum(s => s.Distance),
}).ToList(),
TotalCost = f.VolumeUsed * f.CostPerLitre,
TotalDistance = f.TotalDistance,
VolumeUsed = f.VolumeUsed,
});
StoreAllFields(FieldStorage.Yes);
}
}
现在我不关心索引的数量 - 我想要显示所需的一切,因此查询不必跳转到原始文档。
现在,当我在代码中查询文档时,我在每个计算字段中得到空结果(或 0 对于不可空字段):
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.ToListAsync();
}
返回 JSON:
{
"volumeUsed":28.04,
"costPerLitre":4.93,
"totalDistance":467.3,
"totalCost":null, <----
"averageFuelConsumption":null, <----
"routes":[
{
"startingAddress":"Address 1",
"stops":[
{
"address":"Address 2",
"distance":351.0,
"averageFuelConsumption":6.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
},
{
"startingAddress":"Address 3",
"stops":[
{
"address":"Address 4",
"distance":116.3,
"averageFuelConsumption":7.0
}
],
"totalDistance":0, <----
"totalAverageFuelConsumption":0 <----
}
]
}
当我在 Raven.Studio
中尝试简单的 RavenDb 查询并返回正确的值时,我真的很困惑
from index 'FuelCalculatedIndex'
select TotalCost
看来问题出在C#代码上。我做错了什么?
更新
我刚刚尝试在 C# 中运行原始查询:
await session
.Advanced.AsyncRawQuery<FuelCalculated>("from index 'FuelCalculatedIndex' select TotalCost")
.ToListAsync();
令人惊讶的是,它有效。
查询的结果始终是文档(地图索引)。 所以原来的查询实际上应该是:
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.As<Fuel>
.ToListAsync();
}
您需要使用 ProjectInto 才能获取存储的字段:
using (var session = documentStore.OpenAsyncSession())
{
return await session
.Query<FuelCalculated, FuelCalculatedIndex>()
.ProjectInto<FuelCalculated>
.ToListAsync();
}