使用Nancy和RavenDB构建照片库 我的模型类如下:
[JsonObject(IsReference=true)]
public class Album
{
public Album()
{
this.Photos = new List<Photo>();
this.Tags = new List<String>();
}
public String Id {get; set;}
public String Name {get; set;}
public String Path {get; set;}
public DateTime ModifiedDate{get; set;}
public IList<String> Tags {get; set;}
public IList<Photo> Photos {get; set;}
}
public class Photo
{
public String Id {get; set;}
public String Name {get; set;}
public String Path {get; set;}
public IList<String> Tags {get; set;}
public Album Album {get; set;}
public DateTime ModifiedDate{get; set;}
public bool IsPrivate{get; set;}
}
我在地图上的尝试减少了Photo-&gt;标签的索引:
public class TaggedPhotosIndex:AbstractIndexCreationTask<Album, TaggedPhotos>
{
public TaggedPhotosIndex()
{
Map = albums =>
from a in albums
from p in a.Photos
from t in p.Tags
select new TaggedPhotos
{
Tag = t,
PhotoIds = new List<String> {p.Id}
};
Reduce = results =>
from result in results
group result by result.Tag into agg
select new TaggedPhotos
{
Tag = agg.Key,
PhotoIds = agg.SelectMany(a => a.PhotoIds).ToList()
};
}
}
public class TaggedPhotos
{
public String Tag {get; set;}
public IList<String> PhotoIds {get; set;}
}
这是我想要实现的目标:
给定一个标签数组,我想得到所有至少有一个匹配标签的Photo对象。
RavenDB在查询中不允许使用SelectMany而且没有想法。
找到一个解决方案(使用LuceneQuery @ Workaround for selectmany in ravendb using client api),但期待任何其他替代方案。
答案 0 :(得分:3)
您的文档结构存在一些问题会导致查询困难。
查询设计以返回整个文档。您要求文档提供部分结果。这可以完成,但前提是您将所有字段存储在索引中并从中投影结果。您放弃了文档存储的ACID保证,这是RavenDB最强大的功能之一。
您有Photo
的引用回Album
,这通常会被嵌入,导致循环引用,除非您设置[JsonObject(IsReference=true)]
以避免这种情况。这可能适用于单个文档中的基本序列化,但在从预测索引值引用整个文档时,它毫无意义。你已经设置了自己的“鸡蛋和鸡蛋”问题。
您仍然缺少人们对此问题域的基本功能。具体来说,您应该能够加载一张照片而无需加载整个相册。
我 强烈 建议您将照片放入自己的文档中。然后,您可以使用更简单的索引并避免循环引用。在DDD字词中,Photo
和Album
都是聚合。并且DDD聚合== RavenDB文档。您当前正在将Photo建模为不是聚合的实体,但是您要求的操作只会对聚合进行操作 - 例如搜索。
如果您只询问“给我所有相册包含标有其中一个标签的照片”,那么您就可以了。但你不是要求专辑,而是要求照片。
假设你确实以这种方式建模,Brett的答案很接近 - 但是有一些无关紧要的东西。这是一个显示完整实现的单元测试。在gist上发布,因为它没有直接解决原始问题。 https://gist.github.com/4499724
答案 1 :(得分:1)
这个花了我一段时间但我确认下面的解决方案正在运行。
首先,修改索引和索引结果,如下所示。
public class TaggedPhotosIndex:AbstractIndexCreationTask<Photo, TaggedPhotos>
{
public TaggedPhotosIndex()
{
Map = photos =>
from p in Photos
from t in p.Tags
select new TaggedPhotos
{
Tag = t,
PhotoId = p.Id
};
}
}
public class TaggedPhotos
{
public string Tag {get; set;}
public string PhotoId {get; set;}
}
现在已经创建了索引,您可以通过以下方式查询索引以获取照片。
var tagsToSearch = new List<string>(){"test1", "test2", "test3"};
var photoIds = documentSession.Query<TaggedPhotos, TaggedPhotoIndex>()
.Customize(x => x.Include<Photo>(p => p.Id))
.Where(x => x.Tag.In(tagsToSearch))
.Select(x => x.PhotoId)
.Distinct()
.ToArray();
// This doesn't actually make a second call as the photos are already loaded
// in the document session
var photos = documentSession.Load<Photo>(photoIds);
根据要求
这是我想要实现的目标:
给定一个标签数组,我想获得所有具有的Photo对象 至少一个匹配的标签。
我没有看到专辑是如何真正与之相关的