I have a book database looking like this (simplified):
[book]
- bookId
- title
[author]
- authorId
- name
[book_has_author]
- bookId
- authorId
So basically a book can have multiple authors and an author can have multiples books.
I created an express API that retrieve me a list of books with his authors with an inner join. Here is what it returns for one book having 2 authors:
[
{
bookId: 1,
title: "how to code",
authorId: 1,
name: "martin"
},
{
bookId: 1,
title: "how to code",
authorId: 2,
name: "Tim"
}
]
But my Angular models looks like this:
interface Author {
authorId: number,
name: string,
books: Book[]
}
interface Book {
bookId: number,
title: string,
authors: Author[]
}
I know it's a bad way to represent my database but I don't know how I can model it.
The main issue here is that interfaces have circular referencies to each other, although I imagine you already figured that out.
This is generally a problem and although it's technically correct to think about the data in those terms it's not a good approach to model your data.
The first solution would be to make a choice between having an author have-books or a book have-authors, thus removing one of the dependencies out of the circular reference. You could also create BookChild and AuthorChild interfaces while keeping the Book and Author ones, but that will end up adding unnecessary complexities if the use case isn't really worth it.
After making your choice, you would probably need to add some type safety in your query results. To do that you can create a BookAuthorResponse interface and then transform it to a Book through map and reduce operations or the imperative equivalent (for-loop).
interface Author {
authorId: number,
name: string
}
interface Book {
bookId: number,
title: string,
authors: Author[]
}
interface BookAuthorResponse {
bookId: number
title: string
authorId: number
name: string
}
const bookAuthorResponseArray: BookAuthorResponse[] = [
{
bookId: 1,
title: "how to code",
authorId: 1,
name: "martin"
},
{
bookId: 1,
title: "how to code",
authorId: 2,
name: "Tim"
}
]
const books: Book = bookAuthorResponseArray.map(ba => ({
bookId: ba.bookId,
title: ba.title,
authors: [{
authorId: ba.authorId,
name: ba.name
}]
}))
.reduce((ba, acc) => ({
bookId: ba.bookId,
title: ba.title,
authors: [...acc.authors, ba.authors[0]]
}))
Related
I'm new to mongoDB, and I wonder how I can translate tables relations in MongoDB.
For example in my MySQL base, I have two tables : Manager and Employee.
Manager {
name: String,
ID: Int Primary Key
}
Employee {
name: String,
ID: Int Primary Key,
Manager: int Foreign key (Manager.ID)
}
I would like to know what is the correct way to implement this with MongoDB.
MongoDB is a non-relational document database.
'Document' is a record in a collection and each document can have any number of fields, including arrays, maps, etc. The strength and weakness of this are that two documents in the same collection may hold completely different fields. Normal forms of relational databases do not apply. Also, each document has a unique id.
How to link documents/collections together is completely up to the app logic.
Few options:
Keep everything together in once collection.
//
{
name: "Jon Appleseed",
manager: "Jonh Bosch"
},
{
name:"Another employee",
manager: "Jonh Bosch"
}
Use two collections as suggested by #iprakashv
Use a mixed approach:
// Employees
{
_id: "_234234",
name: "Jon Appleseed",
manager:{
name:"John Bosh",
id: _12321
}
},
{
_id: "_233234",
name: "Another employee",
manager:{
name:"John Bosh",
id: "_12321"
}
}
// Managers
{
_id: _123213,
name:"John Bosh",
subordinates:
[
{name:"Jon Appleseed", id: "_234234" },
{name:"Another employee", id: "_12321" },
]
}
As you see, you gain much more flexibility at the expense of normalization.
As mongodb is a NoSQL database for schema-less and relation-less collections (though you can put validations over a collection), join-less schema and nested objects make more sense here.
Now as per our requirement, each Manager object is linked to its employee so, should ideally have an array containing all its employee objects, but, it is not practical when we need all the employees irrespective of the Manager.
So, we may want to have just the array of employee id's instead of an array of employee objects and employee collection (table) to be maintained separately to fetch employee objects.
The samples documents for the above schema would look like:
//employee collection document
{
"ID": "E12334",
"name": "John Doe"
}
//manager collection document
{
"ID": "M453",
"name": "Jane Doe",
"employeeIDs": ["E12334", "E12343"]
}
react-redux-firebase supports replacing ids with the corresponding value in a lookup object – like a join – through a config object called populates (and later using a convenient mapping function inside mapStateToProps).
Unfortunately, the documentation of react-redux-firebase is rather rudimentary in this area (and in others)...
Can someone tell me, whether it's possible to populate a list of ids?
For example:
// from:
{ friends: [1, 27, 42] }
// to:
{ friends: [
{ id: 1, name: 'Charlie' },
{ id: 27, name: 'Parker' },
{ id: 42, name: 'Brown' },
] }
Testing version 3.0.0, it seems that populating a list works exactly the same as replacing a single field. Instead of receiving back an object you will receive an array of replaced objects.
I have created a controller to handle api requests and return a data provider object, which Yii converts into JSON. (This is done through Yii ActiveController.) Now this model also contains some many-to-many relationships. How can I include the data in the many-to-many relationship in the JSON structure?
Ex.
{ sportsfan: {
id: 1, name: 'Bob', sport: 'Football', teams: [
{ id: 1, name: 'Arsenal'},
{ id:2, name: 'Real Salt Lake' }
]
}
I am going to answer my own question. All I needed to do is the following. I created the following method in my model:
public function fields()
{
return ['id', 'name', 'sport', 'teams'];
}
Note that "id" and "sport" are attributes of the model, "name" is a getter function, "teams" is a relation. Yii2 treats them all the same. This is a great feature!
There is method extraFields() for this purpose (https://github.com/yiisoft/yii2/blob/master/docs/guide/rest-resources.md#overriding-extrafields-)
public function extraFields()
{
return ['teams'];
}
I'm looking to use json from Github's issues api with Ember Data.
The problem is that the return json is not formatted the way ember data wants it to be.
Github returns data as such.
[
{id: 0, title: 'test'},
{id: 1, title: "ect.."}
]
Where as Ember Data's RestAdapter expects it to be like:
{ issues: [
{id: 0, title: 'test'},
{id: 1, title: "ect.."}
] }
I assume based on some research that I need to override the Find and FindAll methods for the DS.RestAdapter
MyApp.Issue = DS.Model.extend({ ... });
MyApp.IssueAdapter = DS.RESTAdapter.extend({
host: 'https://api.github.com/repos/emberjs/ember.js',
find: function(store, type, id) {
...
},
findAll: function(store, type since) {
...
},
}
The problem is in the example if found there are a few out of data methods and it also does not explain how I can pass a array with out an key of "issues"
To be honest I'm really a complete noob to all this and most of this js is over my head but I feel like I'm close to figuring this out. Let me know if I'm on the right track.
I have a customer that uses JSON to represent objects. For example:
var person = {
fname: "John",
lname: "Doe",
nicknames: ["jake", "kevin"]
}
For the purposes of editing these entries, we would like to include GUIDS for each object. A method of embedding the GUIDs has not yet been established. I am currently thinking of doing something like this:
var person = {
_guids: {
fname: "XXX",
lname: "XXX",
_nicknames: "XXX", /* This GUID corresponds to the nickname container */
nicknames: ["jake-guid", "kevin-guid"],
}
fname: "John",
lname: "Doe",
nicknames: ["jake", "kevin"]
}
If each item were to be its own object, it would become exceedingly messy, and would prohibit a clean exchange in cases where the GUIDs are not necessary. However, this approach also leads to the question of how to deal with something like this:
var person = {
_guids: {
fname: "XXX",
lname: "XXX",
sacks_of_marbles: ["container-guid",
"first-sacks-guid", ["XXX", "XXX"],
"second-sacks-guid", ["XXX", "XXX"]]
}
fname: "John",
lname: "Doe",
sacks_of_marbles: [["red", "blue-with-swirls"], ["green", "pink"]]
}
Any recommendations for how to maintain cleanliness, lack of verbosity, as well as the ability to include GUIDs?
In my opinion, the cleanest "identification strategy" is, firstly to include only relevant identifiers, and secondly to include those identifiers within the scope of the object.
In your case, I'd be genuinely shocked to learn that fname and lname require identifiers of their own. They're properties or attributes of an single person object or record. The person will likely have an ID, and the relevant fname and lname values should be easily identified by the person context:
var person = {
id: <guid>,
fname: "Robert",
lname: "Marley",
nicknames: ["Bob Marley"]
};
Or, if the nicknames attribute is actually a list of references, maybe this:
var person = {
id: <guid>,
fname: "Robert",
lname: "Marley",
nicknames: [{id:<guid>,nickname:"Bob Marley"}]
};
If, for some peculiar reason, each name is its own semi-independent record with attributes and identifiers, treat it as a fully qualified object:
var person = {
id: <guid>,
fname: {id:<guid>, name:"Robert"},
lname: {id:<guid>, name:"Marley"},
nicknames: [ {id:<guid>,nickname:"Bob Marley"} ]
};
And while the 3rd example here isn't terribly confusing, it's probably far more verbose than is necessary. I'd highly recommend shooting for the first example and letting context do it's job.
You're not going to get cleanliness or lack of verbosity if you're including GUIDs for everything! That said, one approach would be to turn your property values into hashes like
var person = {
fname: {
value: "John",
guid: "..."
},
lname: {
value: "Doe",
guid: "..."
}
}
This has the advantage that you can nest the GUIDs next to the corresponding values, arbitrarily deeply. However, this will also add some overhead to each access to the object's values (since person.fname will have to become person.fname.value, and so on).
After reviewing the proposals here as well as the use-case, the following solution was adopted, and seems to be working reasonably well.
var person_with_guids = {
obj:{
type: "person",
fname: "fname=guid",
lname: "lname=guid",
nicknames: ["larry-guid", "curly=guid", "moe-guid"],
father: "nick-nolte-guid",
},
refs:{
fname-guid:{
display: "Johnny",
edit: "johnny"
},
lname-guid:{
display: "Walker",
edit: "walker"
},
larry-guid:{
type: "person",
...
}
}
}
var person_without_guids = {
fname: "Johnny",
lname: "Walker",
nicknames: ["Larry", "Curly", "Moe"],
father: {fname: "Nick", lname: "Nolte"}
}
Without getting too far into the specifics of the choice, the listed scheme has the advantage of permitting the guid version to be translated by machine into the sans-guid version. There will be times when a human-readable lightweight JSON will be required, and other times when even the subtle difference between the display-text and the edit-text is required.
This same sort of thing could be accomplished by using schemes proposed above making everything into an object and embedding the guid within it. Doing so, however, causes the guids to be included in an already nested system making it even more difficult to interpret visually. To maintain a more flattened representation, a lookup table methodology was selected.
My thanks to all who responded.