I have a question as follows:
A primary school class contains a number of children and a variety of books. Write a model which keeps track of the books that the children have read. It should maintain a relation hasread between children and books. It should also handle the following events:
record: adds the fact that the given child has read the given book
newbook: outputs a book that the given child has not already read
books_query: outputs the number of books the given child has read
Here is my model so far
CONTEXT
booksContext
SETS
STUDENTS
BOOKS
CONSTANTS
student
book
AXIOMS
axm1: partition(STUDENTS, {student})
axm2: partition(BOOKS,{book})
And my machine is as follows:
MACHINE
books
SEES
booksContext
VARIABLES
students
books
readBooks
INVARIANTS
students ⊆ STUDENTS
books ⊆ BOOKS
readBooks ∈ students → books
I have an event where I want mark a book as read for a given student. It takes in two parameters: the name of the student and the name of the book.
EVENTS
record
ANY
rbook
name
grd1: rbook ∈ books
grd2: name ∈ students
Now for the guards. I want to say
"If the student has not read the book already"
I had this but t doesn't work and I don't know what to do now. Can anyone help me
grd3: rbook(name) = ∅
rbook is just one book, but you are using is as if it was a function. Do you mean readBooks(name) = {}? If yes, the statement would still be "Has the student never read a book?".
The first problem is probably in the definition of readBooks. You modelled it as a total function from students to books. That means that every student has read exactly one book. That is probably not what you wanted to express. To state that every student has read an arbitrary number of books you can map students to sets of books:
readBooks : students --> POW(books)
The the guard would be rbook /: readBooks(name).
Personally I would prefer relations in such a case, they are usually easier to cope with. Here a pair s|->b would be in readBooks if student s has read book b:
readBooks : students <-> books
In that case the guard would be name|->rbook /: readBooks.
Related
I'm new to MongoDB and I'm trying to model a Many to Many relationship into at least 2 collections (I need two collections for the project). What I'm having is a collection of universities, faculties and specializations, and another collection for students and their gradebook (this was the middle entity between specializations and students in SQL, not sure if it's needed in Mongo anymore). I tried to use This as an inspiration but it limits me as I can only search students by university id (I want for example to search students from a certain specialization or a certain faculty). I could put every row from university, faculty and specialization in the student collection and vice versa but I really don't think it's ideal. Here's what I have so far:
db.students.insertOne({_id:1, firstname: 'John', lastname: 'Silas', ethnicity:'english', civilstatus:'single', residence:'London', email:'johnSilas#gmail.com', gradebook:[{ year:2018, registrationyear:2017, formofeducation:'traditional'}], universities:[1]})
db.universities.insertOne({_id:1, name:'University of London', city:'London', adress:'whatever', phone: 'whatever', email: 'whatever#gmail.com', faculty:[{name: 'Law', adress:'whatever', phone: 'whatever', email: 'whatever#gmail.com'}], specialization:[{name:'criminal rights', yearlytax:5000, duration: 3, level:'bachelordegree', language:'english'}], students: [1,2]})
I'm sorry if I don't understand basic noSQL concepts, I am new to it. Thanks in advance.
Basic patterns for many to many association between A and B:
Inline references
On A, store the list of B ids in a field like b_ids
On B, store the list of A ids in a field like a_ids
This requires two writes whenever an association is created or destroyed, but requires either zero or one joins at query time to traverse the association (if you just want the id of Bs for a given A and you have the A already no further queries are needed).
Join model
Create a model C which has two fields: a_id and b_id. Each association is represented by a single instance of C.
This requires one write whenever an association is created or destroyed, but requires joins on all queries involving association (potentially two joins per query).
I have 2 entities.
entity 1 - People
entity 2 - books
People entity has a property which is an array of string names of their favorite books.
I need to create a relationship that somehow maps the favorite book of a person to the corresponding book entity object(s).
I am not sure how to do this.
So far I have started by creating a relationship in core data model for people by setting destination to "books" and then for the books entity creating a relationship by setting destination to "people".
I don't see or understand how this will automatically pick out each of the person's favorite books...at the end of the day they are both seperate objects. How will the people class know that for a specific people instance that this, this and this book are that person's favorite?
Person attribute as array of string names of books -- very bad idea!
You need a to-many relationship with the Book entity. That's it.
Person <------------>> Book
Then, to get an array of book titles for a particular person:
(person.books as! Set<Book>).map { $0.title }
The person can have an additional to-one relationship (e.g. called favoriteBook) to one of the books.
In my application there are N number of Users. Each user can have N number of Categories. Each category can have N number of Books.
I have created following Entities BookMetadata, Users, Categories
BookMetadata entity is a unique collection of books data from different users.
How do I go about creating relationship between these entities.
Relationship between - Users & Categories.(one to many) or users & books (one to many, one user can have one or more than one book).
Relationship between - Categories & Books.(one to many).
Is my understanding about implementing these relationships correct, I'm relatively new in creating relationships in CoreData. If no or a better solution, please let me know how to go about it.
EDIT:
Consider this scenario,
User 1 -> Category 1 -> Book1,Book2.
-> Category 2 -> Book3, Book4.
User 2 -> Category 1 -> Book1,Book2,Book3.
-> Category 3 -> Book4
Here In the above scenario. The same Book (Book 3) has different category for the different user.
How to handle this scenario?
EDIT 2:
I'm attaching a sample sqlite DB file #dropbox https://www.dropbox.com/s/nlmdojkk64bkf1b/test.sqlite.
As a convention Entities should be named as singular. The relationships should be named plural or singular relative to their relationship.
From the given information it is assumed that category is created by a user to group the books like a playlist or something. A category will be unique to user and it is not shared among users. A book can be included in any number of categories.
So this will become
User < -- >> Categories
Category <-- >> Books
Book < -- >> Categories
A relation should have two sides. Inverse let you define that. If a user can have any number of categories and a category can only have one user. Inverse of categories is a user.
So I looked into neo4j, and I may be using it in an upcoming project since its data model might fit my project very well. I looked through the docs but I still need an answer to this question:
Can I set relationships to be one-directional?
It seems that the neo4j people like movies so let's continue with that. If I have a graph like this:
Actor A -> [:Acts in] -> Movie B
then direction is obvious, because the nodes are different types.
But I like horror movies so...
Person A -> [:wants_to_kill] -> Person B
I need this relationship to be one-directional so if I query "Who does Person A want to kill?" I get Person B, if I query "Who does Person B want to kill?" I get nothing.
Sometimes I still need relationships to be two directional
Like:
Person A <-[:has_met] -> Person B
...which is obvious.
documentation says:
Relationships are equally well traversed in either direction. This means that there is
no need to add duplicate relationships in the opposite direction (with regard to
traversal or performance).
While relationships always have a direction, you can ignore the direction where it is
not useful in your application.
So docs say, relationships by default have an direction and I can ignore that if I wish.
Now this is where things get complicated:
Consider the following graph (and note the arrows)
Person A <- [:wants_to_kill] -> Person B
Person B -> [:wants_to_kill] -> Person C
Person C -> [:wants_to_kill] -> Person A
If I ignore the Directions for all [:wants_to_kill] I get false results
for "Who does Person A / C want to kill?"
If I knew which ones I had to ignore, I would not do the query.
So can I somehow set relationships to be two-directional (when creating them), or should I model this with two relationships (between Person A & B)?
A relationship in Neo4j always has a direction. If a relationship type's semantics do not incorporate a direction, e.g. has_met from your example, then it's best practice to apply an arbitrary direction on creation of the relationship. Querying is then done by using the "both directions" (there is no "larger/smaller than" character) notation in cypher:
start ... match (a)-[:HAS_MET]-(b) ....
In contrast, if the semantics of a relationship do have a direction like your wants_to_kill, you need to use two relationship to indicate that a and b wants kill the other one and vice versa. For the example above, you need to have 4 relationships:
Person A -[:wants_to_kill]-> Person B
Person B -[:wants_to_kill]-> Person A
Person B -[:wants_to_kill]-> Person C
Person C -[:wants_to_kill]-> Person A
To find all the person that A wants to kill you do:
start a=node:node_auto_index(name='A') match a-[:wants_to_kill]->victims_of_a return victims_of_a
To find all persons who want to kill A:
start a=node:node_auto_index(name='A') match murderer_of_a-[:wants_to_kill]->a return murderer_of_a
I'm willing to give MongoDB and CouchDB a serious try. So far I've worked a bit with Mongo, but I'm also intrigued by Couch's RESTful approach.
Having worked for years with relational DBs, I still don't get what is the best way to get some things done with non relational databases.
For example, if I have 1000 car shops and 1000 car types, I want to specify what kind of cars each shop sells. Each car has 100 features. Within a relational database i'd make a middle table to link each car shop with the car types it sells via IDs. What is the approach of No-sql? If every car shop sells 50 car types, it means replicating a huge amount of data, if I have to store within the car shop all the features of all the car types it sells!
Any help appreciated.
I can only speak to CouchDB.
The best way to stick your data in the db is to not normalize it at all beyond converting it to JSON. If that data is "cars" then stick all the data about every car in the database.
You then use map/reduce to create a normalized index of the data. So, if you want an index of every car, sorted first by shop, then by car-type you would emit each car with an index of [shop, car-type].
Map reduce seems a little scary at first, but you don't need to understand all the complicated stuff or even btrees, all you need to understand is how the key sorting works.
http://wiki.apache.org/couchdb/View_collation
With that alone you can create amazing normalized indexes over differing documents with the map reduce system in CouchDB.
In MongoDB an often used approach would be store a list of _ids of car types in each car shop. So no separate join table but still basically doing a client-side join.
Embedded documents become more relevant for cases that aren't many-to-many like this.
Coming from a HBase/BigTable point of view, typically you would completely denormalize your data, and use a "list" field, or multidimensional map column (see this link for a better description).
The word "column" is another loaded
word like "table" and "base" which
carries the emotional baggage of years
of RDBMS experience.
Instead, I find it easier to think
about this like a multidimensional map
- a map of maps if you will.
For your example for a many-to-many relationship, you can still create two tables, and use your multidimenstional map column to hold the relationship between the tables.
See the FAQ question 20 in the Hadoop/HBase FAQ:
Q:[Michael Dagaev] How would you
design an Hbase table for many-to-many
association between two entities, for
example Student and Course?
I would
define two tables: Student: student
id student data (name, address, ...)
courses (use course ids as column
qualifiers here) Course: course id
course data (name, syllabus, ...)
students (use student ids as column
qualifiers here) Does it make sense?
A[Jonathan Gray] : Your design does
make sense. As you said, you'd
probably have two column-families in
each of the Student and Course tables.
One for the data, another with a
column per student or course. For
example, a student row might look
like: Student : id/row/key = 1001
data:name = Student Name data:address
= 123 ABC St courses:2001 = (If you need more information about this
association, for example, if they are
on the waiting list) courses:2002 =
... This schema gives you fast access
to the queries, show all classes for a
student (student table, courses
family), or all students for a class
(courses table, students family).
In relational database, the concept is very clear: one table for cars with columns like "car_id, car_type, car_name, car_price", and another table for shops with columns "shop_id, car_id, shop_name, sale_count", the "car_id" links the two table together for data Ops. All the columns must well defined in creating the database.
No SQL database systems do not require you pre-define these columns and tables. You just construct your records in a certain format, say JSon, like:
"{car:[id:1, type:auto, name:ford], shop:[id:100, name:some_shop]}",
"{car:[id:2, type:auto, name:benz], shop:[id:105, name:my_shop]}",
.....
After your system is on-line providing service for your management, you may find there are some flaws in your design of db structure, you hope to add one column "employee" of "shop" for your future records. Then your new records coming is as:
"{car:[id:3, type:auto, name:RR], shop:[id:108, name:other_shop, employee:Bill]}",
No SQL systems allow you to do so, but relational database is impossible for this job.