EdgeDB efficiently writing many to one functions using link - foreign-keys

I am trying to make a one to many links where a user can put in multiple addresses after their name. For example the data can look like this:
name: "Robert Cane"
address:
location: 555 Fake Street
description: Primary address
is_residence: True
location: 123 Foobar Ave.
description: Mailing address
is_residence: False
There are two ways I can do this. Is it better to setup the database this way (similar to writing tables for SQL databases):
type Address {
required property location -> str;
description -> str;
is_residence ->bool;
}
type Person {
required property name -> str;
required multi link address -> Address{
constraint exclusive;
}
}
or this way using the properties inside the multi link (similar to a relationship inside a Graph database). Also note that this is a single, optional entry according to the docs:
type Address {
required property location -> str;
is_residence -> bool;
}
type Person {
required property name -> str;
required multi link address -> Address{
property description -> str;
constraint exclusive;
}
}
My question is are there best practices to do this? Is doing it one way more advantageous in query speed over the other?

Given that "address" is a one-to-many link there is no meaningful distinction between a property of the link and a property of the target object ("Address" in this case) because every target can only be linked at most once. In this situation using a link property is not necessary and not advisable because the same property on the "Address" is going to be easier to access, update, cast into JSON, etc.
Usually you want to use link properties with many-to-many links. In that case there is a significant distinction between the relationship described by the link and the object being linked. You can have multiple different links with different link property values linking to the same target object.
So if you wanted to re-use the same "Address" object for multiple people, then you'd want to put "description" into a link property (what's "home" for one Person is "grandma's house" for another). Incidentally, this scenario makes sense if you expect addresses to be shared and avoiding duplication is useful both for consistency of data and for performance.

Related

How to use Map type in Attribute projections for DynamoDB

I'm trying to design a GSI for my table which contains a lot of data. However I know that its best practice to only project data that I need instead of the entire thing. Projecting data is pretty straight forward when it comes to Top-Level entities but in my use case I also need to project some of the contents of a map object
To give you more detail, here is my partial schema -
Name,
id,
url,
stats {
revenue: {
revenue: 123,
total_orders: 123,
}
social: {}
}
and I want to project name, url and total_orders. Is there a way of projecting all three without projecting the whole stats object ?
Sorry, no. You can only specify by name(s) what attribute to project.
Only top level attributes can be projected. So for your case you would have 2 possible options:
Project the entire stats map if it's not extremely large
Write total_orders as a top level attribute. This would cause duplication but it would be negligible.

What are the trade-offs in Cloud Datastore for list property vs multiple properties vs ancestor key?

My application has models such as the following:
class Employee:
name = attr.ib(str)
department = attr.ib(int)
organization_unit = attr.ib(int)
pay_class = attr.ib(int)
cost_center = attr.ib(int)
It works okay, but I'd like to refactor my application to more of a microkernel (plugin) pattern, where there is a core Employee model that just might just have the name, and plugins can add other properties. I imagine perhaps one possible solution might be:
class Employee:
name = attr.ib(str)
labels = attr.ib(list)
An employee might look like this:
Employee(
name='John Doe'
labels=['department:123',
'organization_unit:456',
'pay_class:789',
'cost_center:012']
)
Perhaps another solution would be to just create an entity for each "label" with the core employee as the ancestor key. One concern with this solution is that currently writes to an entity group are limited to 1 per second, although that limitation will go away (hopefully soon) once Google upgrades existing Datastores to the new "Cloud Firestore in Datastore mode":
https://cloud.google.com/datastore/docs/firestore-or-datastore#in_native_mode
I suppose an application-level trade-off between the list property and ancestor keys approaches is that the list approach more tightly couples plugins with the core, whereas the ancestor key has a somewhat more decoupled data scheme (though not entirely).
Are there any other trade-offs I should be concerned with, performance or otherwise?
Personally I would go with multiple properties for many reasons but it's possible to mix all of these solutions for varying degree of flexibility as required by the app. The main trade-offs are
a) You can't do joins in data store, so storing related data in multiple entities will prevent querying with complex where clauses (ancestor key approach)
b) You can't do range queries if you make numeric and date fields as labels (list property approach)
c) The index could be large and expensive if you index your labels field and only a small set of the labels actually need to be indexed
So, one way to think of mixing all these 3 is
a) For your static data and application logic, use multiple properties.
b) For dynamic data that is not going to be used for querying, you can use a list of labels.
c) For a pluggable data that a plugin needs to query on but doesn't need to join with the static data, you can create another entity that again uses a) and b) so the plugin stores all related data together.

apollo-server - Conditionally exclude fields from selection set

I have a situation where I would like to conditionally exclude a field from a query selection before I hit that query's resolver.
The use case being that my underlying API only exposes certain 'fields' based on the user's locale, and calls made to this API will throw errors if fields are requested that are not included of that locale.
I have tried an approach with directives,
type Person {
id: Int!
name: String!
medicare: String #locale(locales: ["AU"])
}
type query {
person(id: Int!): Person
}
And using the SchemaDirectiveVisitor.visitFieldDefinition, I override field.resolve for the medicare field to return null when the user locale doesn't match any of the locales defined on the directive.
However, when a client with a non "AU" locale executes the following
query {
person(id: 111) {
name
medicareNumber
}
}
}
the field resolver for medicare is never called and the query resolver makes a request to the underlying API, appending the fields in the selection set (including the invalid medicareNumber) as query parameters. The API call returns an error object at this point.
I believe this makes sense as it seems that the directive resolver is on the FieldDefinition and would only be called when the person resolver returns a valid result.
Is there a way to achieve this sort of functionality, with or without directives?
In general, I would caution against this kind of schema design. As a client, if I include a field in the selection set, I expect to see that field in the response -- removing the field from the selection set server-side goes against the spec and can cause unnecessary confusion (especially on a larger team or with a public API).
If you are examining the requested fields in order to determine the parameters to pass to your API call, then forcing a certain field to resolve to null won't do anything -- that field will still be included in the selection set. In fact, there's really no way to create a schema directive that will impact the selection set of a request.
The best approach here would be to 1) ensure any potentially-null fields are nullable in the schema and 2) explicitly filter the selection set wherever your selection-set-to-parameters logic is.
EDIT:
Schema directives won't show up as part of the schema object returned in the info, so they can't be used as flags. My suggestion would be to maintain a separate in-memory map. For example:
const fieldsByLocale = {
US: {
Person: ['name', 'medicareNumber'],
},
AU: {
Person: ['name'],
},
}
then you could just access the appropriate list to filter with fieldsByLocale[context.locale][info.returnType]. This filtering logic is specific to your data source (in this case, the external API), so this is a bit cleaner than "polluting" the schema with information that pertains to the storage layer. If the APIs change, or you switch to a different source for this information altogether (like a database), you can update the resolvers without touching your type definitions. In fact, this way, the filtering logic can easily live inside a domain/service layer instead of your resolvers.

REALM MOBILE PLATFORM sync problems resolution

I have linked list in Realm DB like
ABCD
Each item is Realm object like
{name,next item}
So if I change list on device 1 offline to
ACBD
and on device 2 to
ADBC
and sync after that I get synced DB but wrong cycled list
A -> D -> B -> D .....
How can I solve this problem?
Is there possibility to get synced objects after sync on clients and to correct lists before realm Results notifications will be launched?
Update.
I also tried to use such model for hierarchical lists
class MList: Object {
dynamic var name = ""
let items = List<MItem>()
}
class MItem: Object {
dynamic var name = ""
let subitems = List<MItem>()
}
I have used data
A
B
1.
A
-B
2.
B
-A
After sync but list lost all items. So such data struct is unsuitable for my task.
Alright, I see the problem.
Manually maintaining a linked list structure unfortunately won't work, because Realm sees each link update as a regular property update without knowledge about the item's position in the list. Therefore the list updates cannot be merged in the expected way when multiple participants update the list, and the result will be duplicates, cycles, or leaked objects.
Instead, I suggest you use Realm's built-in list type, which will merge correctly. You will still have a problem related to the parent field in your data model, whereby if two participants change the value, the last one to do so will "win". I'm not sure what your exact use case is, so this may or may not be fine. Notably it probably won't be fine if you perform tree rotations, in which case you will end up leaking objects from the graph or creating unexpected cycles.
The best long-term solution is for Realm to introduce a proper CRDT tree type, but so far there hasn't been demand for this. If trees are a fundamentally requirement in your data model, I suggest creating a feature request for CRDT trees in our GitHub repository.
Can you use Realm's own lists? They have quite an elaborate merging logic that supports element moves/reorderings: https://realm.io/docs/javascript/latest/#list-properties
Now I have the model
class MList: Object {
dynamic var name = ""
dynamic var firstItem: PLItem?
}
class MItem: Object {
dynamic var name = ""
dynamic var next: PLItem?
dynamic var parent: PLItem?
}
I use "next" to order list and "parent" to create the tree structure.

Presenting missing values as null or not at all in JSON

I am building a web service API, using JSON as the data language. Designing the structure of the data returned from the service, I am having some trouble deciding how to deal with missing values.
Consider this example: I have a product in my web store for which the price is yet unknown, maybe because the product has not yet been released. Do I include price: null (as shown below) or do I simply omit the price property on this item?
{
name: 'OSX 10.6.10',
brand: 'Apple',
price: null
}
My main concern is making the API as easy to consume as possible. The explicit null value makes it clear that a price can be expected on a product, but at the other hand it seems like wasted bytes. There could be a whole bunch of properties that are completely irrelevant to this particular product, while relevant for other products – should I show these as explicitly null as well?
{
name: 'OSX 10.6.10',
price: 29.95,
color: null,
size: null
}
Are there any "best practices" on web service design, favoring explicit or implicit null values? Any de-facto standard? Or does it depend entirely on the use case?
FWIW, my personal opinion:
Do I include price: null (as shown below) or do I simply omit the price property on this item?
I would set the values of "standard" fields to null. Although JSON is often used with JavaScript and there, missing properties can be handled similarly as the ones set to null, this must not be the case for other languages (e.g. Java). Having to test first whether a field is present seems inconvenient. Setting the values to null but having the fields present would be more consistent.
There could be a whole bunch of properties that are completely irrelevant to this particular product, while relevant for other products – should I show these as explicitly null as well?
I would only include those fields that are relevant for a product (e.g. not pages for a CD). It's the client's task to deal with these "optional" fields properly. If you have no value for a certain field which is relavant to a product, set it to null too.
As already said, the most important thing is to be consistent and to clearly specify which fields can be expected. You can reduce the data size using gzip compression.
i don't know which is "best practice". But i usually don't send fields that i don't need.
When i read response, i check if value exists:
if (res.size) {
// response has size
}