これが私がそれにアプローチする方法です。これは、RaccoonBlog PostComments に基づいています。
各ユーザーのイベントを別のドキュメント (つまり、以下の例では UserEvent) に保存し、ユーザーには、それにリンクする追加のプロパティと、ユーザーに関連付けられた最後のイベントのタイムスタンプを追加します。これにより、ユーザードキュメントははるかに小さくなりますが、多くの重要な情報が含まれます
UserEvent では、ID、このドキュメントが参照するユーザー ID へのリンク、「イベント」コレクション、および lasteventid を保持する単純なドキュメントになります。このようにして、各「イベント」は、必要に応じてメンテナンス用のサブドキュメントになります。
最後に、データを簡単にクエリできるようにする UserEvent のインデックス
public class User
{
public string Id { get; set; }
// other user properties
public string UserEventId { get; set; }
public int NumberOfEvents { get; set; }
public DateTimeOffset LastEvent { get; set; }
}
public class UserEvent
{
public string Id { get; set; }
public string UserId { get; set; }
public int LastEventId { get; set; }
public ICollection<Event> Events { get; protected set; }
public int GenerateEventId()
{
return ++LastEventId;
}
public class Event
{
public int Id { get; set; }
public DateTimeOffset CreatedAt { get; set; }
public string ActivityType { get; set; }
// other event properties
}
}
public class UserEvents_CreationDate : AbstractIndexCreationTask<UserEvent, UserEvents_CreationDate.ReduceResult>
{
public UserEvents_CreationDate()
{
Map = userEvents => from userEvent in userEvents
from evt in userEvent.Events
select new
{
evt.CreatedAt,
EventId = evt.Id,
UserEventId = userEvent.Id,
userEvent.UserId,
evt.ActivityType
};
Store(x => x.CreatedAt, FieldStorage.Yes);
Store(x => x.EventId, FieldStorage.Yes);
Store(x => x.UserEventId, FieldStorage.Yes);
Store(x => x.UserId, FieldStorage.Yes);
Store(x => x.ActivityType, FieldStorage.Yes);
}
public class ReduceResult
{
public DateTimeOffset CreatedAt { get; set; }
public int EventId { get; set; }
public string UserEventId { get; set; }
public string UserId { get; set; }
public string ActivityType { get; set; }
}
}
public static class Helpers
{
public static DateTimeOffset AsMinutes(this DateTimeOffset self)
{
return new DateTimeOffset(self.Year, self.Month, self.Day, self.Hour, self.Minute, 0, 0, self.Offset);
}
public static IList<Tuple<UserEvents_CreationDate.ReduceResult, User>> QueryForRecentEvents(
this IDocumentSession documentSession,
Func
<IRavenQueryable<UserEvents_CreationDate.ReduceResult>, IQueryable<UserEvents_CreationDate.ReduceResult>
> processQuery)
{
IRavenQueryable<UserEvents_CreationDate.ReduceResult> query = documentSession
.Query<UserEvents_CreationDate.ReduceResult, UserEvents_CreationDate>()
.Include(comment => comment.UserEventId)
.Include(comment => comment.UserId)
.OrderByDescending(x => x.CreatedAt)
.Where(x => x.CreatedAt < DateTimeOffset.Now.AsMinutes())
.AsProjection<UserEvents_CreationDate.ReduceResult>();
List<UserEvents_CreationDate.ReduceResult> list = processQuery(query).ToList();
return (from identifier in list
let user = documentSession.Load<User>(identifier.UserId)
select Tuple.Create(identifier, user))
.ToList();
}
}
次に、クエリを実行するために必要なことは、次のようなものです。
documentSession.QueryForRecentEvents(q => q.Where(x => x.UserId == user.Id && x.ActivityType == "asfd").Take(20)).Select(x => x.Item1);