Some background
I'm working on a data-intensive UI where state is stored in a Redux container. Anyone who has ever touched Redux knows there's a lot of repetitive boilerplate to be written in the form of reducers, actions, action creators, selectors (analogous to queries), and so on.
There's no fun in writing these, especially when there's a lot of entity types and accompanying relationships involved.
Therefore, the idea is to devise a relational schema together with a code generator to which the heavy lifting can be outsourced.
Problem
Given a (hypothetical) relational schema like the following:
const schema = {
book: {
attributes: ["id", "name", "subGenreId"],
foreignKeys: [
{ fromAttribute: "subGenreId", toEntity: "subGenre", toAttribute: "id" }
]
},
mainGenre: {
attributes: ["id", "name"]
},
subGenre: {
attributes: ["id", "name", "mainGenreId"],
foreignKeys: [
{ fromAttribute: "mainGenreId", toEntity: "mainGenre", toAttribute: "id" }
]
},
author: {
attributes: ["id", "name"]
},
book_author: {
attributes: ["bookId", "authorId"],
foreignKeys: [
{ fromAttribute: "bookId", toEntity: "book", toAttribute: "id" },
{ fromAttribute: "authorId", toEntity: "author", toAttribute: "id" }
]
},
seller: {
attributes: ["id", "name"]
},
seller_book: {
attributes: ["sellerId", "bookId"],
foreignKeys: [
{ fromAttribute: "sellerId", toEntity: "seller", toAttribute: "id" },
{ fromAttribute: "bookId", toEntity: "book", toAttribute: "id" }
]
}
};
The goal is to (computationally, of course) generate selectors along these lines (probably forgot a few):
"direct" relationships:
books by subGenre id
mainGenre by subGenre id
subGenre by book id
subGenres by mainGenre id
many-to-many relationships (omitted the junction tables themselves):
authors by book id
books by author id
books by seller id
sellers by book id
"distant" relationships (this is where it gets interesting):
authors by mainGenre id
authors by seller id
authors by subGenre id
books by mainGenre id
mainGenre by book id
mainGenres by author id
mainGenres by seller id
sellers by author id
sellers by mainGenre id
sellers by subGenre id
subGenres by author id
subGenres by seller id
There are also more complex (e.g. circular) relationships like co-authors, but I don't mind manually writing code for these when the need arises.
How would one go about enumerating these associations between entities? Are there pre-existing solutions? I can imagine graph traversal being involved, but perhaps it is better solved using methods I'm not yet aware of.
Related
My firestore document structure looks like this
doc1
{
name: 'Test',
categories: [
{
allNames: ['name1', 'name2', 'name3],
id: 'abcd'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
doc2
{
name: 'Test2',
categories: [
{
allNames: ['name7'],
id: 'abcd3'
},
{
allNames: ['name4', 'name5'],
id: 'xyz'
},
]
I am using the JS SDK and wanted to query all document with a certain category(id or name). So if I query with categories.id equal to xyz or categories.allNames contains name1, both the above documents should be returned.
Are both these queries possible or do I need to remodel my data ?
Thank you !
You cannot query arrays that way. If you know the exact object then you could use array-contains as shown below:
firestore.collection('col').where('categories', 'array-contains', {id: 'abc', allNames: ['name1']})
One solution would be to store another array which contains category IDs only like this:
{
name: 'Test1',
categories: [...],
categoryIds: ['abcd', 'xyz']
}
Now you can use arrayContains even if you know the category ID only and not the whole object in categories array. The same method can be used for allNames.
Categories can also be made a sub-collection where each object in categories array would be a document. Then you can use Collection Group queries to find category documents with that ID or allNames and find parent document ID using the DocumentReference.
I have an object with an array and an object. I iterate the array (fields) - using it as a template to create form elements. I want to - in the process - get the corresponding object value from the object (data).
{
"fields": [
{
"name": "id",
"type": "int",
"max_length": 11,
},
{
"name": "email",
"type": "varchar",
"max_length": 191,
}
],
"data": {
"id": "4",
"email": "person#domain.com",
}
}
Something like this (mind map):
{{#each fields}}
<li>
lookup {{lookup ../data => VALUE OF CORRESPONDING KEY ("id" or "email" etc.)}}
<label for="{{name}}">{{CamelCase name}}</label>
{{InputType name type}}
</li>
{{/each}}
So, when the field name is 'id' I'd like to grab the value of 'id' from the object etc.
I can't seem to wrap my head around the lookup ... or are there some other more clever and direct way of achieving this?
I think you summarized the desired logic very well when you said "when the field name is 'id' I'd like to grab the value of 'id' from the object".
In other words, you want to perform a lookup on the data Object and the value of the name variable is the key to be looked up.
The lookup would be simply: {{lookup ../data name}}. name will evaluate to the desired key to be looked-up on the context object ../data.
Thanks, ended up doing this (passing the data to the helper):
{{#each fields}}
<li>
<label for="{{name}}">{{CamelCase name}}</label>
{{InputType name type ../data }}
</li>
{{/each}}
And then in the helper extracted the value by doing:
Handlebars.registerHelper("InputType", function ( name, type, value) {
switch ( type ) { …
… value="' + value[name] + '">');
I have two entities. Categories and Products. Each product can have many categories and each category can belong to many categories. I would like to be able to return all products and for each one to have all the categories it belongs to and their parent categories. Is datastore a good option for something like this?
example Product response:
{
id: 1,
name: "shoes",
categories: [{
id:1,
ordinal:1
},{
id:2,
ordinal:1
}]
}
I assume you meant 'Datastore' where you wrote 'dataflow'
It depends if you want to query later based on categories or not.
In case you won't need to query based on categories
I'd suggest defining your categories in a model (with the appropriate parent/child relationships) and then adding each category to a product in a LocalStructuredProperty. Datastore will save as a blob but will reconstruct the category entity model when you retrieve the product. You could also add a JsonProperty with a serialized string containing the category structure for each product. For example:
[
0: {
category: 'Electronics',
subcategories: ['Smartphones', 'Telephones', 'Gadgets']
},
1: {
category: 'Apple',
subcategories: ['iPhone']
}
]
Read more about the LocalStructuredProperty and the JsonProperty here (for Python client library).
If you need to query based on categories
Then you should use a StructuredProperty. Create a model to define your categories and their ancestor paths. Then you add one or more categories (along with their parents) to the Product entity when you instantiate it.
The Entity Property Reference in Datastore documentation has a good example of how to implement it (in Python, but also available for other languages). And here's how you filter for StructuredProperty values.
When define a schema with ydn-db I can define a single column as PK with this code:
var products = {
name: 'products',
keyPath: 'id_product',
autoIncrement: true,
indexes: [
{keyPath: 'id_product'},
{keyPath: 'id_supplier'}
]
};
var schema = {
stores: [products]
};
How I can define a Store (table) with one PK with two columns or more? Thanks
How I can define a Store (table) with one PK with two columns or more?
I am not sure answering your question. IndexedDB (ynd-db is very IDB centric) can have only one PK. But primary key can be compound key compose of multiple keyPath (column) using array keypath. It is define like this
var products = {
name: 'products',
keyPath: ['id_category', id_product']
};
I have two entities, invoices and sales tax. Recently my team has decided to upgrade to Symfony 2.3 from 2.1. We had to rewrite a lot of the ways we were doing queries because of this, and some entities that didn't have relationships needed to have them.
Before the update, my invoices and sales tax records were created by getting the transaction id date('U'); and setting up both with the same transaction id (both tables have a primary index id as well).
So you can imagine it looks like this:
Sales Tax: id, transaction_id, amount
Invoice: id, transaction_id, amount
So when I queried for them I just joined on the transaction id. Now joins aren't working without relationships, so I'm having to update this to have a relationship. But when I go to create an invoice or sales tax record, I get this error: Notice: Undefined index: transactionId in C:\folders\vendor\doctrine\orm\lib\Doctrine\ORM\Persisters\BasicEntityPersister.php line 539.
In the code the sales tax record is being created just fine, but when it goes to create the invoice it fails:
public function insertSalesTax($transactionId, $amount)
{
$tax = new SalesTax();
$tax->setAmount($amount);
$tax->setTransactionId($transactionId);
$this->entityManager->persist($tax);
$this->entityManager->flush();
return $tax;
}
That inserts, but then I take that tax record and try to create the invoice:
$invoice = new Invoice();
$em = $this->entityManager;
$invoice //omitted other invoice data
->setSalesTax($salesData['salesTax']);
$em->persist($invoice);
$em->flush();
Here's the relevant portions of my mapping in yml:
Bundle\Entity\Invoice:
type: entity
table: invoices
indexes:
transactionId:
columns: [ transaction_id ]
id:
id:
type: integer
generator: { strategy: AUTO }
manyToOne:
salesTax:
targetEntity: SalesTax
inversedBy: invoice
joinColumn:
name: transaction_id
referencedColumnName: transaction_id
And SalesTax:
Bundle\Entity\SalesTax:
type: entity
table: sales_taxes
indexes:
transactionId:
columns: [ transaction_id ]
id:
id:
type: integer
generator: { strategy: AUTO }
oneToMany:
invoice:
targetEntity: Invoice
mappedBy: salesTax
If you're wondering why oneToMany, that's because invoices are stored as individual line items. There may be many invoices with the same transaction ID. One transaction ID in the invoices table represents one order, each row only represents a line item. So this invoice entity will probably need a self-referencing relationship at some point.