Neo4j - Array inside an array inside a relationship - arrays

For a few days now, I've been designing a social network database structure and I've been optimizing over and over again the data structures.
What I am trying to achieve in Neo4j:
I am trying to create a relationship between two nodes which has a property called "history" and one called "currentStatus". The problem is that both are (should be) arrays. Something like:
MATCH (u:User {username: 'john.snow#gmail.com'}), (uu:User {username: 'sansa.stark#gmail.com'})
MERGE u-[rel:FRIENDSHIP]->uu
ON CREATE SET rel.previousFriendshipUpdates = [], rel.currentFriendshipStatus = [sentTime: timestamp(), status: '0']
ON MATCH SET rel.previousFriendshipUpdates = [rel.previousFriendshipUpdates + rel.currentFriendshipStatus], rel.currentFriendshipStatus = [sentTime: timestamp(), status: '1']
I want to keep a history of whatever actions regarding they're friendship take place (sender sent friend request at x time, receiver rejected friend request at x time, sender sent friend request (again) at x time, receiver accepted at x time, receiver unfriended sender at x time, etc).
Thank you in advance.

To add values to array (collection) property arr on relationship r you can do
SET r.arr = r.arr + 'newvalue'
or
SET r.arr = r.arr + ['onevalue', 'nothervalue']
(see How to push values to property array Cypher-Neo4j)
But arrays cannot contain values like sentTime: timestamp(). That looks like a property and an array can't have properties.
Nodes can have properties, however, and both the structure of your example query and the description of your model suggests that you represent the friendship as a node instead. Let each :Friendship node have [:MEMBER] relationships to two :User nodes. Then keep the friendship status as a property on that node. A good way to model relationship history could be to create a node for each update and keep these in a "linked list" that extends from the :Friendship node.

Related

Django, handling m2m change signals over a model with multi ManyToManyField

I have a model M contains three manytomanyfields(a,b,c) to three different models in django.
class M (models.Model):
name = models.CharField()
a = models.ManyToManyField(A)
b = models.ManyToManyField(B)
c = models.ManyToManyField(C)
Now, I want to handle any changes on my model M and send an HttpRequest to an url correspondingly.
as you know in post-save signal of model M the values of attributes for a,b and c are not set yet because they will be set when saving model M has been finished.(the rule of ManyToManyField)
I write a single handler for my model to handle any changes(either create a new instance or update a field/fields)
#receiver(post_save, sender=M)
#receiver(m2m_changed, sender=M.a.through)
#receiver(m2m_changed, sender=M.b.through)
#receiver(m2m_changed, sender=M.c.through)
def M_changes_handler(sender, **kwargs):
is_instance_set_compeletly(kwargs['instance']):
#send_and_HttpRequest(url, data = instance)
def is_instance_set_compeletly(kwargs['instance']):
if M.a.all() is not None and M.b.all() is not None and
M.c.all()is not None
flag = True
else:
flag = False
return flag
Now consider an update request (which changes all fields) on model M will send signals for all fields a,b and c; so three httpRequests would send to my sender with three different versions of instance! on the other hand when user just changes a field for example b of the model M this function will send only one httpRequest.
I want to handle this problem dynamically and just send one request per ANY TYPE of CHANGE on my model M.
I was wondering if somebody could help me :)
*Note the code above is just a draft and may contains syntax error so ignore them ;)
Update: My problem solved!
The process of saving a model containing m2mfields is interesting!
First of all the fields of M which are not m2m fields type e.g. are char field, foreign key or etc. had been set before calling post_save. So in post_save their values are updated
Although m2mfields wont be set till the saving of the model would be finished. Then m2mchange signals called to set m2mfields
The only way to have an updated version of your model is to overriding form save in admin.py because the "form save" will be called after finishing all m2mfields have been set
Solution:
For all stack-overflow users and Dear Blake Gibbs
If a model contains manytomany fields and you want to access all the data of a saved record, you cannot access those m2m fields because they will save after finishing the process of saving model(consider M in my example), then assign that Id to other self-created m2m table to bind that Id to m2m fields (e.g. A in my example). so overriding the save method of a model in admin.py does not work in this case.
I simply override the save function of my form in Forms.py
class MForm(forms.ModelForm):
class Meta:
model = M
exclude = []
def save(self, commit=True):
query = ""
old_instance = super(MForm, self).save(commit=False)# if you need the old instance
#otherwise return super(MForm, self).save(commit=True)
instance = super(MForm,self).save(commit=True)
in this case the "instance" is really saved completely and you can access m2m fields by using ".all()"
hope it helped!
you can hold previously instance of M and in post_save with new M check field have changed according to that you can send request.

Modelling with ndb

I'm quite new to ndb. This is how my structure looks like in general:
a = [b, c]
b = [d, e, f]
d = [g, h]
e = [k, l, m, n]
f = [o]
c = [p, r, t]
I have the following model.
class Child(ndb.Model):
name = ndb.StringProperty()
child = ndb.KeyProperty(kind="Child", repeated=True)
class Root(ndb.Model):
name = ndb.StringProperty()
child = db.StructuredProperty(Child, repeated=True)
I can't do this since ndb won't allow me to repeat it because I already repeat Child.
What would be the proper way to model this structure?
Since the entities of the Root and Child kinds are almost the same, The data I see you are trying to model is a classic example of one-to-many relationship between entities of the same kind. The modelling for this sort of relationship is below:
class RelatedKind(ndb.Model):
name = ndb.StringProperty()
root = ndb.KeyProperty(kind="RelatedKind")
To create entities:
a = RelatedKind(name='a')
a_key = a.put()
b = RelatedKind(name='b', root=a_key)
b_key = b.put()
c = RelatedKind(name='c', root=a_key)
c_key = c.put()
# To get all 'child' of a;
child_a = RelatedKind.query(root == a_key).fetch()
print(child_a)
# >>> [b_key, c_key]
With datastore query, and just keyproperty, you achieve the same modelling without using repeated.
If you just want to be able to store many 'Child' entities on a single 'Root', you can use a LocalStructuredProperty to contain the Child model instead (but this means it won't be indexed). There's a hint to this behavior in the App Engine NDB docs when it discusses nested structured properties:
Although a StructuredProperty can be repeated and a StructuredProperty can contain another StructuredProperty, beware: if one structured property contains another, only one of them can be repeated. A work-around is to use LocalStructuredProperty, which does not have this constraint (but does not allow queries on its property values).
Another option for modeling nested relationships like this would be to use ancestors on the keys. So, for example, let's say your Root key path were: ('Root', 1). You could add children below it with keys ('Root', 1, 'Child', 1), ('Root', 1, 'Child', 5), and so on, appending 'Child' to the keypath each time. Then, we you wanted to query for the children of an object, you could just use an ancestor query, e.g.:
def create_child(parent, name):
new_child = Child(parent=parent.key, name=name)
new_child.put()
return new_child
def get_children(parent):
return Child.query(ancestor=parent.key)
class Child(ndb.Model):
name = ndb.StringProperty()
class Root(ndb.Model):
name = ndb.StringProperty()
You don't really even need to have a Root anymore at this point, because you can assign any arbitrary keypath, and you could also use the name as an ID instead and store less information.
That said, it's really completely dependent on what you're actually trying to model, there's not really enough information here to understand what you mean.
I don't see why you need a KeyProperty on the child. You could model your relationship like so:
class Child(ndb.Model):
name = ndb.StringProperty()
class Root(ndb.Model):
name = ndb.StringProperty()
child = ndb.KeyProperty(repeated=True)
c1 = Child(name="b").put()
c2 = Child(name="c").put()
a = Root(child=[c1,c2]).put() # put returns the key; otherwise you would need c1.key() here
children_keys = a.get().child # [Key(Child, 1234), Key(Child, 4567)]
# to retrieve the children, you could do
children = [ key.get() for key in children_keys ]
Keep in mind a few things. Suppose that you imagine records as being like files on your filesystem.
A KeyProperty is a pointer to another file.
A repeated property just stores multiple values.
There's no reason to use a structured property at all in this example, so let's skip that.
So, if you have the "root" object "contain" all the children via a repeated property, that'll result in you having a root file that can only be updated once every second or so, and it'll eventually grow too large.
So, in lieu of that, you have a few choices. You can use use ancestor queries, like Jeff mentioned. Or, you can just use all pointers and use a query to child any node's children:
class Node(ndb.Model):
parent = ndb.KeyProperty(kind='Node')
def get_children(self):
return Node.query().filter(Node.parent == self.key)
You can use get_children to fetch any node's children. Note that this part is eventually consistent, so recently added nodes won't necessarily show up in get_children for generally only a second or so.
root = Node(parent=None)
child1 = Node(parent=root)
child2 = Node(parent=root)
child3 = Node(parent=root)
sub_child1 = Node(parent=child1)

What is the best practice way to initialize an actor from the database

I have a top level actor (under the guardian), called Groups which on startup needs to load the list of groups from the database and create a bunch of child actors based on those groups in the database.
I have placed the database load code inside of the preStart function as I don't want any messages to be processed before the groups are loaded.
Currently my Groups actor looks like this;
var groups: Map[String, ActorRef] = Map()
override def preStart() = {
groups = getGroupsFromDB() map createGroup
}
def createGroup(pair: (String, Long)) = {
val (name, id) = pair
val group = context.actorOf(Props(new Group(id, name)), name = name)
name -> group
}
However I don't believe this is the best way to handle this, as what happens if the database server is not available? So what is the best pratice way of handling data initialization from a database?
The Akka documentation explains how to supervise top level actors for fault-tolerance.
You can apply the principles there to manage the exceptions you may find if the DB is not available.

Python - read with key in App Engine

I have a python program in Google App Engine
When finding an object in the datastore when I have the key as a string, how can I do a direct read. Below is my code which is performing a loop, not good.....
class Opportunity(db.Model):
customer = db.ReferenceProperty(Customer,collection_name='opportunitys')
BNusername = db.StringProperty()
opportunity_no = db.StringProperty()
# etc etc etc.....
#BnPresets holds the object key as a string
opportunitys = Opportunity.all()
opportunitys.filter('BNusername =',BnPresets.myusername)
for oprec in opportunitys:
if str(oprec.key()) == BnPresets.recordkey:
opportunity = oprec
# I have the object here and can process etc etc
You can instantiate db.Key from string by passing it directly to the constructor:
opportunity_key = db.Key(BnPresets.recordkey)
Once you have that, simply db.get to obtain the entity identified by this key:
opportunity = db.get(opportunity_key)
I guess (by looking at the query you use) that you also want to verify the username of the object you got:
if opportunity.BNusername == BnPresets.myusername
process_opportunity(opportunity)
That should be pretty much it. The bottom line is that you should use the key first - as it uniquely identifies your entity - rather than querying for some other property and iterating through results.

Queries with JDOQL Unique Result Set

In my GAE application I want to make a JDOQL which returns a List where every element exist at most once even in the database there are more. How can I do this?
I dont know about JDOQL, but if you want a list where each entity exists utmost once i.e each list element is unique, then you could do the following:
Asume you have an entit type / model class that we call Type, with attributes att1,attr2.
You want to have a list of unique elements based on one or more of the attributes, say attr2.
you can use the following method that I adapted from a good source on the issue:
def unique(seq, idfun=None):
''' A function that returns a list of unique items in a very efficient manner
Refer to : http://www.peterbe.com/plog/uniqifiers-benchmark '''
# order preserving
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
# in old Python versions:
# if seen.has_key(marker)
# but in new ones:
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result
the to get a list of unique elements from the datastore type Type based on attr2 i could do something like:
list = Type.all()
unique_list = unique(list,lambda t: t.attr2)
Hope this helps because it has been the best method for me so far.

Resources