Вопрос

I've been doing some research on Nosql (RavenDB in particular) and I'm still unsure of the best way to approach the following:

I have two simple objects, 'user' and 'events'. A user can enter many events and an event can be entered by many users - a standard many to many relationship. I'm trying to get out of the relational database mindset!

Here are the queries/actions that I'd like to run against the database:

  • Get me all the events that a user has not entered
  • Get me all the events that a user has entered
  • Update all the events (properties like remaining spaces) very frequently (data polled from various external data sources).
  • Removing events when they've expired

So from what I've read, I have several options:

  1. Create a new object, that links user and events. For example, a "booking" object, that stores the userId, eventId.

    This seems the most logical to me, but it feels rather 'relational database' approach?

  2. Denormalise the events data within the user object, so there is a list of eventIds on the user.

    Seems sensible, but wouldn't this make querying from both directions difficult?

  3. Don't use RavenDB for this, instead use a relational database.
What would you suggest to be the best way to handle this, based on the details above?

Many thanks,

Dan C

Это было полезно?

Решение

Actually, RavenDB is a perfect fit for that. To properly do that, ask yourself what are the main entities in your model? each one of those will be a document type in RavenDB.

So in your scenario, you'd have Event and User. Then, an Event can have a list of User IDs which you can then easily index and query on. There are more ways to do that, and I actually discussed this in my blog some time in the past with some further considerations that might come up.

The only non-trivial bit is probably the index for answering queries like "all events user has not entered", but that's quite easily done as well:

public class Events_Registrations : AbstractIndexCreationTask<Event>
{
        public Events_Registrations()
        {
                Map = events => from e in events
                              select new { EventId = e.Id, UserId = e.Registrations.SelectMany(x => x.UserId) });

        }
}

Once you have such an index in place, you can do a query like below to get all events a specified user has no registrations to:

var events = RavenSession.Advanced.LuceneQuery<Event, Events_Registrations>()
                                .Where("EventId:*")
                                .AndAlso()
                                .Not
                                .WhereEquals("UserId", userId).ToList();

Then handling things like expiring events etc is very easily done. Definitely don't denormalize event data in the User object, it will make your life living hell.

There's some data missing though - for example how many registrations are allow per event. If there are too many you may want to break it out of the actual Event object, or to revert to Booking objects as you mention. I discuss this in length in my book RavenDB in Action (shameless plug, I know, but its just too long to actually discuss here).

Другие советы

Not knowing the exact reqs and intended use makes a design rec a bit chancy. That said, I'd say go with option 2. That's the most logical structure.

Then create indexes to support the other types of views you need. You don't specify it in your question but you probably want to see what users have entered a single event. That's accomplished with an index.

"Removing events". Do you really want to remove them? I think you want to be able to list all "active" events. Right? If so that's also accomplished easily with an index.

I'd say use a mindset of "Aggregate Roots" when designing your entities and use indexes to support your queries. Please also note that RavenDB indexes is not the same as indexes in a RDBMS. You could in some extent think of a RavenDB index as a RDBMS "View".

Also know there are different type of RavenDB indexes. These types are not very clear distinguished in the client programming interface (I've found that being a big defect in Raven, it still confuses me). Browsing the indexes in the studio is a good way to understand the data in indexes.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top