How would you model the places visited by 2 or more people on a given date? Seems like it should be pretty simple but I don't get how to relate them to be able to say, User 1 and User 2 visited X on y date or how to say they visited X together on the same date.
I started this GraphViz to help visualise it:
digraph visit_example {
node [shape = doublecircle]; "User 1" "User 2";
node [shape = circle];
"User 1" -> Alaska [ label = "Visits" ];
"User 2" -> Alaska [ label = "Visits" ];
"Jan 1st" -> Date [label = "is a"];
"Mar 7th" -> Date [label = "is a"];
"Dec 9th" -> Date [label = "is a"];
}
How would you change the above to say, User 1 visited Alaska on March 7th with User 2? Independently, User 1 visited Alaska on Jan1st and User 2 on Dec 9th?
The advantage (and sometimes inconvenient) of a graph database is that such use cases can be modeled in multiple fashions.
It depends also on what kind of queries you would want to do.
Let's say, you'll never query by time and if you would do, query time is not important, you can easily put the date on the relationship property.
(a:User)-[:VISITED {time:0123456789}]->(p:Place)
If, you want to query by date, then you can for e.g., have a :Visit node representing the visit of the user and have a time property on it
(a:User)-[:DO_VISIT]->(v:Visit {time: 123456789})-[:IN_PLACE]->(p:Place)
Then you can query all :Visit nodes by time
Another solution is to manage a time tree, for e.g. GraphAware's TimeTree
Then your Visit node will be automatically attached to a TimeTree
(:Year {value:2015})-[:CHILD]->(:Month {value:7})-[:CHILD]->(:Day {value:8})<-[:EVENT_TIME]-(v:Visit)<-[:DO_VISIT]-(:User)
There are certainly other ways to model it, try the one that best fit your needs and performance of queries
Related
I'm making a HTTP request to a REST API I created which contains two tables in the DBMS, the main table is called Levels looks like this
Levels:
leve_id: 1
level: "Level 1"
I have a child table called Units that looks like this
Units:
primary_id: 1
unit: "Unit 1"
unit_id: 1 ,foreign key to level_id
I have inserted "unit 1" and "unit 2" to this table and they both have the unit_id: equal to 1 because I want them in Level 1.
Now, the problem is when I'm trying to use a forEach loop in swiftUI to show the units.
struct UnitView: View {
#StateObject var unitVm = UnitViewModel()
var body: some View {
List(unitVm.units, id:\.idUnit){ unit in
Text(unit.unit)
}
}
}
It gives me an error of "ID 1 occurs multiple times"
Which is understandable since the foreign keys aren't unique,
could anyone point me in the right direction to show multiple units with the same id in a particular level?
It's a bit unclear what data you're working with, exactly, in terms of the UnitViewModel, but I'm guessing that it's a direct translation of the Units table, ie with four fields corresponding to: primary_id, unit, unit_id, and level_id.
For the purposes of the swiftUI List, it just needs each item to be uniquely identifiable (eg when you say scrollTo(someItemID)), so you should just supply it the path to your primary_id (which I assume is unique for the whole table) and all should work well. It won't care about the duplicates in idUnit, at that point.
In my app I have some videos and users can like it. video metadata saves in the node "videos", something like this:
videos: {
xxxxx: {
name: "Funny video",
likes: 255,
....
}
}
And I have another node "userVideos" only with video ids.
userVideos: {
xxxxx: true,
yyyyy: true,
}
In the UI I want to show the ranking of the video. For example, I have 5 videos: v01 has 5 likes, v02 - 10, v03 - 1, v04 - 100, v05 - 3.
So, when I get from userVideos the video with id "v03", I should know that his ranking is 5 ('cause if I get the videos list with orderBy DESC my videos node, the position of v03 is 5).
I think that the cloud function should calculate this ranking.
My question is next: is I have a possibility to get the position in the sorted node by key?
Realtime Database queries can't tell you the position of a child snapshot in a sorted query. You have to write code to maintain that data for yourself.
For clarity purpose, step names are used as identifiers
I have the following Directed Acyclic Graph (DAG):
What I'm trying to do is select a node, and find all the other nodes that are not connected directly to the selected one, only in an outbound direction.
For example: if I select "root step", my query should only return "test step 3", since it is the only one not connected directly to "root step".
However, if I select "test step 2", it should only return "test step 3", and not "test step", because "test step* is at the same level that "test step 2" is.
For now, here is how I do:
I store, in every "step", the list of parents it has as an array. (test step has ["root step"], etc.)
My query is as follows ( for test step 2 as an example ):
FOR v, e IN 0..10 OUTBOUND "steps/test step 2" steps_relations
FILTER e._from != "steps/test step 2"
FILTER e._to != "steps/test step 2"
FILTER v._id != "steps/test step 2"
FILTER ["root step"] NONE IN v.parents
RETURN {id: v._key, name: v.name }
For now it returns an empty result instead of the expected ("test step 3"). Any help is greatly appreciated
I have finally managed to fix this. Here is how I did it:
first, I added two fields to each one of my "steps" document:
root: equals true when it is the root of the tree (like "root step"). Otherwise it simply references the internal ID of the root step
depth: equals to 0 for the root step, but is incremented. When I add a step to another, the new step's depth equals (parent + 1) ONLY if the result is bigger than the one actually stored.
Once I have this, my query looks as follows:
Situation: I want to list all the steps that can be linked to "test step 2"
FOR step, relation IN 0..10 ANY "steps/root step" steps_relations
FILTER step.depth > 1 /* THE DEPTH OF test step 2 WICH IS 1 */
FILTER relation._from != "steps/test step 2"
RETURN item
This returns successfully "test step 3"
You should rather use the min attribute to suppress edges directly connected:
FOR v, e IN 2..10 OUTBOUND "steps/test step 2" steps_relations
RETURN {id: v._key, name: v.name }
this way you will only get paths longer than one edge-hop, and the vertices from 2 onwards.
I'm trying to copy a vertex node and retain it's relationships in ArangoDB. I'm getting a "access after data-modification" error (1579). It doesn't like it when I iterate over the source node's edges and insert an edge copy within the loop. This makes sense but I'm struggling to figure out how to do what I'm wanting within a single transaction.
var query = arangojs.aqlQuery`
let tmpNode = (FOR v IN vertices FILTER v._id == ${nodeId} RETURN v)[0]
let nodeCopy = UNSET(tmpNode, '_id', '_key', '_rev')
let nodeCopyId = (INSERT nodeCopy IN 'vertices' RETURN NEW._id)[0]
FOR e IN GRAPH_EDGES('g', ${nodeId}, {'includeData': true, 'maxDepth': 1})
let tmpEdge = UNSET(e, '_id', '_key', '_rev')
let edgeCopy = MERGE(tmpEdge, {'_from': nodeCopyId})
INSERT edgeCopy IN 'edges'
`;
This quesion is somewhat similar to 'In AQL how to re-parent a vertex' - so let me explain this in a similar way.
One should use the ArangoDB 2.8 pattern matching traversals to solve this.
We will copy Alice to become Sally with similar relations:
let alice=DOCUMENT("persons/alice")
let newSally=UNSET(MERGE(alice, {_key: "sally", name: "Sally"}), '_id')
let r=(for v,e in 1..1 ANY alice GRAPH "knows_graph"
LET me = UNSET(e, "_id", "_key", "_rev")
LET newEdge = (me._to == "persons/alice") ?
MERGE(me, {_to: "persons/sally"}) :
MERGE(me, {_from: "persons/sally"})
INSERT newEdge IN knows RETURN newEdge)
INSERT newSally IN persons RETURN newSally
We therefore first load Alice. We UNSET the properties ArangoDB should set on its own. We change the properties that have to be uniq to be uniq for Alice so we have a Sally afterwards.
Then we open a subquery to traverse ANY first level relations of Alice. In this subequery we want to copy the edges - e. We need to UNSET once more the document attributes that have to be autogenerated by ArangoDB. We need to find out which side of _from and _to pointed to Alice and relocate it to Sally.
The final insert of Sally has to be outside of the subquery, else this statement will attempt to insert one Sally per edge we traverse. We can't insert Saly in front of the query as you already found out - no subsequent fetches are allowed after the insert.
Right now my flashcard game is using a prepvocab() method where I
define the terms and translations for a week's worth of terms as a dictionary
add a description of that week's terms
lump them into a list of dictionaries, where a user selects their "weeks" to study
Every time I add a new week's worth of terms and translations, I'm stuck adding another element to the list of available dictionaries. I can definitely see this as not being a Good Thing.
class Vocab(object):
def __init__(self):
vocab = {}
self.new_vocab = vocab
self.prepvocab()
def prepvocab(self):
week01 = {"term":"translation"} #and many more...
week01d = "Simple Latvian words"
week02 = {"term":"translation"}
week02d = "Simple Latvian colors"
week03 = {"I need to add this":"to self.selvocab below"}
week03d = "Body parts"
self.selvocab = [week01, week02] #, week03, weekn]
self.descs = [week01d, week02d] #, week03, weekn]
Vocab.selvocab(self)
def selvocab(self):
"""I like this because as long as I maintain self.selvocab,
the for loop cycles through the options just fine"""
for x in range(self.selvocab):
YN = input("Would you like to add week " \
+ repr(x + 1) + " vocab? (y or n) \n" \
"Description: " + self.descs[x] + " ").lower()
if YN in "yes":
self.new_vocab.update(self.selvocab[x])
self.makevocab()
I can definitely see that this is going to be a pain with 20+ yes no questions. I'm reading up on curses at the moment, and was thinking of printing all the descriptions at once, and letting the user pick all that they'd like to study for the round.
How do I keep this part of my code better maintained? Anybody got a radical overhaul that isn't so....procedural?
You should store your term:translation pairs and descriptions in a text file in some manner. Your program should then parse the text file and discover all available lessons. This will allow you to extend the set of lessons available without having to edit any code.
As for your selection of lessons, write a print_lesson_choices function that displays the available lessons and descriptions to the user, and then ask for their input in selecting them. Instead of asking a question of them for every lesson, why not make your prompt something like:
self.selected_weeks = []
def selvocab(self):
self.print_lesson_choices()
selection = input("Select a lesson number or leave blank if done selecting: ")
if selection == "": #Done selecting
self.makevocab()
elif selection in self.available_lessons:
if selection not in self.selected_weeks:
self.selected_weeks.append(selection)
print "Added lesson %s"%selection
self.selvocab() #Display the list of options so the user can select again
else:
print "Bad selection, try again."
self.selvocab()
Pickling objects into a database means it'll take some effort to create an interface to modify the weekly lessons from the front end, but is well worth the time.