Properties on Datomic ref relationships - datomic

I'm trying to model a schema where a list can have many items and each item can belong to many lists. It's clear to me that I can have a :list/items ref type to model the relationship, but I'd like to also have a rank attribute which determines an item's position in each list where it exists. How might one do such a thing?

The only answer I have - assuming that positioning is list dependent - is that you need to add an indirecting entity with a rank attribute. This isn't very pleasant. It would be nice if a many relation could be ordered, as this use case would simplify substantially.

Heterogenous tuples, added in June 2019, are a new modelling option here.
An attribute value, i.e. the v in the eavto 5-tuple, can now itself be a tuple. This is a clojure vector of max length 8.
Official blog post announcement.
Discussion of the release on twitter.
Note the example in the docs above uses
:db/tupleTypes [:db.type/long :db.type/long]
which is a little strange as the point is heterogenous tuples, so in the case of the OP this would be:
{:db/ident :list/item
:db/valueType :db.type/tuple
:db/tupleTypes [:db.type/ref :db.type/long] ; ref to item, rank
:db/cardinality :db.cardinality/many}
Or you could use a value type instead of a ref for item, if that works for you.
To use this in datalog, you can use the tuple and untuple functions.

Related

How to filter based on the last element in ArrayField in django

I'm using postgresql database which allows having an array datatype, in addition django provides PostgreSQL specific model fields for that.
My question is how can I filter objects based on the last element of the array?
class Example(models.Model):
tags = ArrayField(models.CharField(...))
example = Example.objects.create(tags=['tag1', 'tag2', 'tag3']
example_tag3 = Example.objects.filter(tags__2='tag3')
I want to filter but don't know what is the size of the tags. Is there any dynamic filtering something like:
example_tag3 = Example.objects.filter(tags__last='tag3')
I don't think there is a way to do that without "killing the performance" other than using raw SQL (see this). But you should avoid doing things like this, from the doc:
Tip: Arrays are not sets; searching for specific array elements can be
a sign of database misdesign. Consider using a separate table with a
row for each item that would be an array element. This will be easier
to search, and is likely to scale better for a large number of
elements.
Adding to the above answer and comment, if changing the table structure isn't an option, you may filter your query based on the first element in an array by using field__0:
example_tag3 = Example.objects.filter(tags__0='tag1')
However, I don't see a way to access the last element directly in the documentation.

Database design for variable number of attributes

I am trying to come up with a schema for an Oracle db. The problem is as follows:
The database should represent an attribute (- say a url) associated with a variety of attributes for a variety of values.
For Example:
The database should have the mapping:
If attribute-X has value-X ==> Url-X
If attribute-Y has value-Y ==> Url-Y
If attribute-X has value-X && attribute-Y has value-Y ==> Url-XY
Also the number of attributes is not defined, so these cannot correspond to a attribute in the db.
The workaround I have thought is to store it as a multi name value-pair and use the same to look up in the database.
For example:
**attribute** **Key** **Value**
attribute-X value-X Url-X
attribute-Y value-Y Url-Y
attribute-X&attribute-Y value-X&value-Y Url-XY
I am new to databases and I am aware that is is not a neat representation of the data model. Is there a better way to represent this ?
You could model this with one table, but then you would need to keep adding attributes (new column for each new attribute), which is not a good design.
You can however, model this so you can add attributes types, then add the attribute dynamically.

Explanation of eval attribute in product.template in OpenErp

I need to understand the eval attribute in the following code in the product_demo.xml in product module in Odoo:
"record id="product_product_4_product_template" model="product.template">
field name="attribute_line_ids" eval="[(6,0,[ref('product.product_attribute_line_1'), ref('product.product_attribute_line_2'), ref('product.product_attribute_line_3')])]"/>
</record>"
I understand that the attribute_line_ids value is being set here. I also understand that the values inside the 'ref' refers to XML ids which would, in short, return the model-'product.attribute.line associate with the XML id.
I really don't understand what each of the values in the eval attribute mean and what changes would it do on view level and db level. I have referred to many odoo documentation but none could provide clarity.
This adds a bunch of values to a Many2many field called attribute_line_ids. Odoo has a special syntax for setting values on Many2many fields. This syntax is described here and is used in the code you asked about.
Basically, to modify a many2many relation you use a three-element tuple. The first element of the tuple is a numeric command, and two other elements are values - their exact function depend on the command.
There are six numeric commands:
0 - creates a new object and adds it to the Many2many relation
1 - updates an object that already exists on the relation
2 - deletes an object that already exists on the relation
3 - removes an existing object from the relation, without deleting it
4 - adds an existing object to the relation
5 - removes all objects from the relation, without deleting them
6 - replaces pervious objects existing on the relation with a new set of objects
The relevant part of your code look like this:
(6,0,[ref('product.product_attribute_line_1'), ref('product.product_attribute_line_2'), ref('product.product_attribute_line_3')])
It's a three-element tuple (which is expected, since the code sets values on a Many2many relation):
The first element is the command. "6" means elements previously existing in the relation (if any) will be replaced with elements which ids are passed as the third element of the tuple.
The second argument is irrelevant. It has a role with other commands, but when used with "6" it can be anything (personally I would use None to better reflect this).
The third element is a list of ids. Since the first element is "6", this signifies the objects that will be put into the relation, replacing whatever was previously there.

Projection query with new fields/properites ignores entries that haven't set those properties yet

I have an Article type structured like this:
type Article struct {
Title string
Content string `datastore:",noindex"`
}
In an administrative portion of my site, I list all of my Articles. The only property I need in order to display this list is Title; grabbing the content of the article seems wasteful. So I use a projection query:
q := datastore.NewQuery("Article").Project("Title")
Everything works as expected so far. Now I decide I'd like to add two fields to Article so that some articles can be unlisted in the public article list and/or unviewable when access is attempted. Understanding the datastore to be schema-less, I think this might be very simple. I add the two new fields to Article:
type Article struct {
Title string
Content string `datastore:",noindex"`
Unlisted bool
Unviewable bool
}
I also add them to the projection query, since I want to indicate in the administrative article list when an article is publicly unlisted and/or unviewable:
q := datastore.NewQuery("Article").Project("Title", "Unlisted", "Unviewable")
Unfortunately, this only returns entries that have explicitly included Unlisted and Unviewable when Put into the datastore.
My workaround for now is to simply stop using a projection query:
q := datastore.NewQuery("Article")
All entries are returned, and the entries that never set Unlisted or Unviewable have them set to their zero value as expected. The downside is that the article content is being passed around needlessly.
In this case, that compromise isn't terrible, but I expect similar situations to arise in the future, and it could be a big deal not being able to use projection queries. Projections queries and adding new properties to datastore entries seem like they're not fitting together well. I want to make sure I'm not misunderstanding something or missing the correct way to do things.
It's not clear to me from the documentation that projection queries should behave this way (ignoring entries that don't have the projected properties rather than including them with zero values). Is this the intended behavior?
Are the only options in scenarios like this (adding new fields to structs / properties to entries) to either forgo projection queries or run some kind of "schema migration", Getting all entries and then Puting them back, so they now have zero-valued properties and can be projected?
Projection queries source the data for fields from the indexes not the entity, when you have added new properties pre-existing records do not appear in those indexes you are performing the project query on. They will need to be re-indexed.
You are asking for those specific properties and they don't exist hence the current behaviour.
You should probably think of a projection query as a request for entities with a value in a requested index in addition to any filter you place on a query.

Mongoid Syntax Questions

1) Finding by instance object
Assuming I have the instance object called #topic. I want to retrieve the answers for this given topic. I was thinking I should be able to pass in :topics=>#topic, but i had to do the very ugly query below.
#answers = Answers.where(:topic_ids => {"$in" => [#topic.id]})
2) Getting the string representation of the id. I have a custom function (shown below). But shouldn't this be a very common requirement?
def sid
return id.to_s
end
If your associations are set up correctly, you should be able to do:
#topic.answers
It sounds like the above is what you are looking for. Make sure you have set up your associations correctly. Mongoid is very forgiving when defining associations, so it can seem that they are set up right when there is in fact a problem like mismatched names in references_many and referenced_in.
If there's a good reason why the above doesn't work and you have to use a query, you can use this simple query:
#answers = Answer.where(:topic_ids => #topic.id)
This will match any Answer record whose topic_ids include the supplied ID. The syntax is the same for array fields as for single-value fields like Answer.where(:title => 'Foo'). MongoDB will interpret the query differently depending on whether the field is an array (check if supplied value is in the array) or a single value (check if the supplied value is a match).
Here's a little more info on how MongoDB handles array queries:
http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-ValueinanArray

Resources