How to fix my m..n relationship in nosql (mongodb)? - sql

At first I'm trying to make a rally (you know cars with drivers...) database. I have two collections: drivers { name, address, sex, ... } and then another one tournaments { name, location, price, ... }
I try to keep it simple. In a tournament there should be drivers (because a tournament without drivers...well its not nice ^^). And there is my problem, in a normal sql database I could select two primary keys (lets say name in drivers and name in tournaments - just to keep it simple, I know name as primary key is not nice). And because its an m..n relationship (is it right?) I would make a 3. Table with the two primary keys. OK that would be easy. But how should I solve this problem in mongodb. I thought something like: tournaments { name, location, price, ... drivers { driver_1, ..., driver_n } } , but im not sure. I'm using Java so I could make some special Classes which one is handling this relationship problem? I don't understand the other mongodb tutorials. Any ideas? Thank you for any help!

There are a few ways to do this:
As #Gianluca describes you can perform this linking manually by adding a driver's _id ObjectId or another identifying property (probably one you have a unique index on) to a "drivers" array in a tournament document. e.g. tournament : { ... drivers : ["6019235867192384", "73510945093", ...]}
Another option specifically built for this referencing is the DBRef specification which provides a more formal method probably more similar to what you're familiar in the SQL world. DBRef is supported by the java driver and allows you to scope your reference to a collection (basically saying where this reference comes from). I wouldn't be surprised if in the future versions of MongoDB cross-collection queries will be supported, although they are not currently.
More information here.
Also if you aren't using a DAO framework I would suggest Morphia which supports DBRef with a nice #Reference annotation.

I solved the problem using the _id field that every document had and is unique.
So in you case you just need to create a collection that has the ObjectId of the torunaments and some ObjectId from the collection drivers. Or you can just put the ObejctId of the driver directly in the torunaments collection. Probably not the best solution, but it work
Gianluca

Add an array field drivers in the trournaments type and put the _ids of the drivers in there.
To add/remove drivers, just update the field. There is no need for an intermediary N:M mapping table unless the array gets really huge.
If it gets huge, the usual solution is to cut the array into several smaller ones and save them in several documents that you can look up quickly by using the id_ of the container (the tournament). Removing and sorting is then a pain, of course.

Related

Kotlin same map same Object by multiple keys

I have a list of objects that looks like:
data class Student(
val id: Int,
val name: String,
val gpa: Long,
val age: Int
)
I wanna have 2 maps:
student.name -> Student
student.id -> Student
But I don't wanna duplicate the maps.
What would be the best way to achieve this?
I've tried to map Student.id->Student.name and use this but wanted to be sure there is no standard solution already exists for that in Kotlin.
Thanks
Honestly, just make two maps. That's what you want anyway - you have two mappings, id to Student and name to Student. You need a map for each.
Those properties just happen to be stored in the Student object - but imagine if they weren't, would you mind having two maps then? One for separateIdentifier1 to Student, and one for separateIdentifier2 to Student? That would be fine, right - it's just what you have to do!
And if you only had one of those embedded properties, like student.id - would you say "I don't want to make a map because that attribute is already stored in the data"? No, you'd still make the map, right? Because you're not storing data, you're creating a fast lookup that's generated from that data. And it's exactly the same principle if you're creating two or more lookups. And you're not duplicating the objects, just adding an entry of object reference to object reference
Really you just want to generate derived maps, where your actual data is the collection of Student objects, and the mappings for id and name are just automatically generated. You need to ensure that when (if) you add or remove a Student, that both mappings get updated, and that those updates happen together, atomically. Handle concurrency if you need to, that kind of thing.
There's nothing like that in the Kotlin standard library, which is more focused on core functional components you can bolt together into more specialised things. I can't see anything similar in Guava either - they have MultiMaps (one key to many values) and Tables (a pair of keys to a single value) but nothing where you have multiple keys that can be used interchangeably. Just roll your own I reckon!

DB relationship depends on table type

I am trying to find the name of my problem:
A Comment table contains comments made by User on either a Concert or Play or Album or Painting, etc.
I am trying to avoid using many different comment tables CommentPlay, CommentAlbum!
This is perhaps a one-to-many relationship until I want to search for all Comments under a specific Play. There must be a comment_type (e.g. for_play, for_album) somewhere but I do not know how to include that in the relationship.
I am accessing the database using abstract SQL (Perl's DBIx::Class) and would like to remain db-vendor agnostic (among SQLite, MySQL, Pg).
Could someone give me a pointer as to what exactly is the name of the situation I am facing?

Why use sql tags in struct in some go libs like gorm?

Well I know the necessity of tags in struct in golang and how is it accessed by reflect in golang. But I have searched and could not find a reliable answer to the question of why I should use sql tags in struct while writing struct for sql results. I have explored many sample code and people are using sql:"index" in the struct and sql:"primary_key" in the struct.
Now I have done indexing in the database layer, isn’t it enough? Should I have to use sql:"index" too get the best results? Like so I have defined primary key attribute in the database should I have to specify sql:"primary_key" as well?
My code seems to work fine without those. Just want to know their benefit and usages.
I think you are referring to an ORM library like gorm
In that case, metadata like sql:"primary_key" or sql:"index" will just tell the ORM to create an index while trying to setup the tables or maybe migrate them.
A couple of examples in gorm could be: indexes, primary keys, foreign keys, many2many relations or when trying to adapt an exiting schema into your gorm models, setting the type explicitly, like for example:
type Address struct {
ID int
Address1 string `sql:"not null;unique"` // Set field as not nullable and unique
Address2 string `sql:"type:varchar(100);unique"`
Post sql.NullString `sql:"not null"`
}
Depends on the package you are using and your use-case. Is it enough for CRUD? Almost always, unless the package says so which is often rare but possible. Few packages sometime do under the hood magic which may give rise to bugs. If you are aware of these behaviours, or are quite explicit in your code, you'll probably avoid it.
Indexing tags mostly allows you to use package's migration tools translating your model declaration into sql queries (CREATE statements). So if you always want to do this by yourself, then you probably needn't bother adding such tags.
But you may find yourself a bug if your package requires a tag. For example, in case of gorm, the Model method takes a struct pointer as an input. If this struct has a field named ID it uses it as a primary key, that is, say ID has a value of "4", it will add a WHERE id=4 automatically. In case your struct has ID, you needn't even add a primary_key tag and it will still be treated as one. This behaviour may cause issues when you have both a "non-primary-key" ID field, and another field which you are actually using as the primary key. Another example for gorm is this. A possible behaviour can also be checking for nullable property and throwing an error if an INSERT statement involves a NOT NULL field getting a NULL value.
On a different note, adding tags to your structs can be considered good practice since it gives context of its properties in the DB.

How To Override Default LINQ to SQL Association Name

I am working on a pretty straight forward C# application that uses LINQ to SQL for database access. The application is a non-web (i.e. thick client) application.
The problem that I have recently run into is with the default association name that LINQ to SQL is creating for fields that are foreign keys to another table. More specifically, I have provided an example below:
Example of Problem
The majority of my combo boxes are filled using values from a reference data table (i.e. RefData) that stores a type, description, and a few other fields. When the form initially loads, it fills the combo boxes with values based on a query by type. For example, I have a form that allows the user to add customers. On this form, there is a combo box for state. The stateComboBox is filled by running a query against the RefData table where type = stateType. Then, when the user saves the customer with a selected state the id of the RefData column for the selected state is stored in the state column of the customer table. All of this works as expected. However, if my customer table has more than one column that is a foreign key to the RefData table it quickly becomes very confusing because the association name(s) created by LINQ are Customer.RefData, Customer.RefData1, Customer.RefData2, etc... It would be much easier if I could override the name of the association so that accessing the reference data would be more like Customer.State, Customer.Country, Customer.Type, etc...
I have looked into changing this information in the DBML that is generated by VS but, my database schema is still very immature and constantly requires changes. Right now, I have been deleting the DBML every day or two to regenerate the LINQ to SQL files after making changes to the database. Is there an easy way to create these associations with meaningful names that will not be lost while I frequently re-create the DBML?
I am not sure LINQ to SQL is the best method of accessing data, period, but I find it even more problematic in your case.
Your real issue is you have the concept of your domain objects fairly static (you know what the program needs to use to get work done), but you are not sure how you are persisting the data, as your schema is in flux. This is not a good scenario for automagic updates.
If it were me, I would code the domain models so they do not change except when you desire change. I would then determine how to link to the persistent schema (database in this case). If you like a bit more automagic, then I would consider Entity Framework, as you can use code first and map to the schema as it changes.
If you find this still does not help, because your database schema changes are incompatible with the domain models, you need to get away from coding and go into a deeper planning mode. Otherwise, you are going to continue to beat your head against the proverbial wall of change.
Create a partial class definition for your Customer table and add more meaningful getter properties for the LINQ to SQL generated member names:
public partial class Customer
{
public string Name { get; set; }
[JsonIgnore]
public RefData State => this.RefData;
[JsonIgnore]
public RefData Country => this.RefData1;
}
I blogged about this here

Accessing the join table in a hql query for a many-to-many relationship in grails

I have 2 domain classes with a many-to-many relationship in grails: decks and cards.
The setup looks like this:
class Deck {
static hasMany = [cards: Card]
}
class Card {
static hasMany = [decks: Deck]
static belongsTo = Deck
}
After I delete a deck, I want to also delete all cards which no longer belong to a deck. The easiest way to accomplish this is to write something like the following sql:
delete from card where card.id not in(select card_id from deck_cards);
However, I can't figure out how to write a HQL query which will resolve to this SQL because the join table, deck_cards, does not have a corresponding grails domain class. I can't write this statement using normal joins because HQL doesn't let you use joins in delete statements, and if I use a subquery to get around this restriction mySQL complains because you're not allowed to refer to the table you're deleting from in the "from" section of the subquery.
I also tried using the hibernate "delete-orphan" cascade option but that results in all cards being deleted when a deck is deleted even if those cards also belong to other decks. I'm going crazy - this seems like it should be a simple task.
edit
There seems to be some confusion about this specific use of "decks" and "cards". In this application, the "cards" are flashcards and there can be tens of thousands of them in a deck. Also, it is sometimes necessary to make a copy of a deck so that users can edit it as they see fit. In this scenario, rather than copying all the cards over, the new deck will just reference the same cards as the old deck, and if a card is changed only then will a new card be created. Also, while I can do this delete in a loop in groovy, it will be very slow and resource-intensive since it will generate tens of thousands of sql delete statements rather than just 1 (using the above sql). Is there no way to access a property of the join table in HQL?
First, I don't see the point in your entities.
It is illogical to make a card belong to more than one deck. And it is illogical to have both belongTo and hasMany.
Anyway, Don't use HQL for delete.
If you actually need a OneToMany, use session.remove(deck) and set the cascade of cards to REMOVE or ALL.
If you really want ManyToMany, do the checks manually on the entities. In pseudocode (since I don't know grails):
for (Card card : deck.cards} {
if (card.decks.size == 0) {
session.remove(card);
}
}
I won't be answering the technical side, but challenging the model. I hope this will also be valuable to you :-)
Functionally, it seems to me that your two objects don't have the same lifecycle:
Decks are changing : they are created, filled with Cards, modified, and deleted. They certainly need to be persisted to your database, because you wouldn't be able to recreate them using code otherwise.
Cards are constant : the set of all cards is known from the beginning, they keep existing. If you delete a Card once in the database, then you will need to recreate the same Card later when someone needs to put it in a Deck, so in all cases you will have a data structure that is responsible for providing the list of possible Cards. If they are not saved in your database, you could recreate them...
In the model you give, the cards have a set of Decks that hold them. But that information has the same lifecycle than the Decks' (changing), so I suggest to hold the association only on the Deck's side (uni-directional Many-To-Many relationship).
Now you've done that, your Cards are really constant information, so they don't even need to be persisted into the database. You would still have a second table (in addition to the Deck), but that Card table would only contain the identifying information for the Card (could be a simple integer 1 to 52, or two values, depending what you need to "select" in your queries), and not other fields (an image, the strength, some points etc...).
In Hibernate, these choices turns the Many-To-Many relationship to a Collection of values (see Hibernate reference).
With a Collection of Values, Card is not an Entity but a Component. And you don't have to delete them, everything is automatically taken care by Hibernate.