0

I'm working on a side project to create a Forum built on top of RavenDB. I am currently trying to work out the relationship between Authors of Topics, and the "Last Reply" user on a topic. In a typical relational model I would simply store the FK to the User who posted the topic, and have a join off to the replies table to get the most recent replies author. This is obviously not the use case for Raven or any Document store for that matter.

What would be the most "optimal" way of pulling this off? Currently I'm tossing around a couple ideas.

Idea 1: Save the FK of the Author on the Topic model, add a JsonIgnored User object that I will populate on the Topic load by using an Include in my session load (so one request so far from the client side, just makes the Load itself and model a bit complicated). Then possibly using a map-reduce index to get the most recent replies author (or even the same method as getting the Topic Author, so 1 or 2 queries depending).

Idea 2: Saving both the Author and the most recent reply User on the model. Main "problem" here is the potential for stale data (say if a username changes). However that could potentially be alleviated with a background task (or simply keeping that in mind when updating a user document and going back over all posts from a user).

Example of the models in question.

public class User
{
    public string Id { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
}

public class Topic
{
    public string Id { get; set; }
    public string Title { get; set; }
    public string Body { get; set; }

    // Idea 1 Relationships
    public string AuthorId { get; set; }
    [JsonIgnore]
    public User Author { get; set; } // Would need to be populated on loads from an Include on AuthorId
    public string MostRecentReplyUserId { get; set; }
    [JsonIgnore]
    public User MostRecentReplyUser { get; set; } // Same as Author

    // Idea 2 Relationships
    public User Author { get; set; }
    public User MostRecentReplyUser { get; set; }
}

Note: I would likely add a method to the User model to return a "clean" version where I scrub out things like the PasswordHash and use that on the Save for Idea 2.

Justin Packwood
  • 337
  • 2
  • 12

1 Answers1

0

Depending on your needs in case of update and query performance both ways may be the better choice.

I personally would recommend the first idea because you don't need to update existing documents when some data changes on the user records. Using include on query/load time is quite a nice feature of ravendb which can help you when retrieving nested records from the database. Just make sure that you don't forget to include all nested documents - otherwise you may get many roundtrips.

Embedding documents (like Idea 1 but with a stored value of the users) may be better if your data processing is seperated from the data retrieval and you don't have access to the database session when converting data to be handed out to the frontend. We're using such a system that heavily relies on that (getting one input and mapping out a json pendant of the value) - this seperates data retrieval logic completely from the output (like mapping to json) logic. Downside here: You've to make sure that existing (embedded) data get's updated whenever a user changes and the data that is transferred over the wire is more than on idea 1.

Daniel Nachtrub
  • 366
  • 1
  • 6